hal: add usb audio tunnel support

This patch imports the USB audio tunnel feature from QCOM software release
AU_LINUX_ANDROID_LA.UM.5.7.R1.07.00.00.253.

Bug: 33030406
Test: playback, record and path switching

Change-Id: I2479f984c0d72b2f4e9b6a7db22eb4616855b7e7
Signed-off-by: David Lin <[email protected]>
diff --git a/hal/Android.mk b/hal/Android.mk
index c2801db..062e3d3 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -74,6 +74,11 @@
   LOCAL_SRC_FILES +=  $(AUDIO_PLATFORM)/hw_info.c
 endif
 
+ifeq ($(strip $(AUDIO_FEATURE_ENABLED_USB_TUNNEL)),true)
+    LOCAL_CFLAGS += -DUSB_TUNNEL_ENABLED
+    LOCAL_SRC_FILES += audio_extn/usb.c
+endif
+
 LOCAL_SHARED_LIBRARIES := \
 	liblog \
 	libcutils \
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index f53c9f2..b734cb6 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -70,6 +70,31 @@
 
 #endif
 
+#ifndef USB_TUNNEL_ENABLED
+#define audio_extn_usb_init(adev)                                      (0)
+#define audio_extn_usb_deinit()                                        (0)
+#define audio_extn_usb_add_device(device, card)                        (0)
+#define audio_extn_usb_remove_device(device, card)                     (0)
+#define audio_extn_usb_is_config_supported(bit_width, sample_rate, ch, pb) (false)
+#define audio_extn_usb_enable_sidetone(device, enable)                 (0)
+#define audio_extn_usb_set_sidetone_gain(parms, value, len)            (0)
+#define audio_extn_usb_is_capture_supported()                          (false)
+#else
+void audio_extn_usb_init(void *adev);
+void audio_extn_usb_deinit();
+void audio_extn_usb_add_device(audio_devices_t device, int card);
+void audio_extn_usb_remove_device(audio_devices_t device, int card);
+bool audio_extn_usb_is_config_supported(unsigned int *bit_width,
+                                        unsigned int *sample_rate,
+                                        unsigned int *ch,
+                                        bool is_playback);
+int audio_extn_usb_enable_sidetone(int device, bool enable);
+int audio_extn_usb_set_sidetone_gain(struct str_parms *parms,
+                                     char *value, int len);
+bool audio_extn_usb_is_capture_supported();
+#endif
+
+
 #ifndef SOUND_TRIGGER_ENABLED
 #define audio_extn_sound_trigger_init(adev)                            (0)
 #define audio_extn_sound_trigger_deinit(adev)                          (0)
diff --git a/hal/audio_extn/usb.c b/hal/audio_extn/usb.c
new file mode 100644
index 0000000..3747318
--- /dev/null
+++ b/hal/audio_extn/usb.c
@@ -0,0 +1,1034 @@
+/*
+ * 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_usb"
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <system/audio.h>
+#include <tinyalsa/asoundlib.h>
+#include <audio_hw.h>
+#include <cutils/properties.h>
+#include <ctype.h>
+#include <math.h>
+
+#ifdef USB_TUNNEL_ENABLED
+#define USB_BUFF_SIZE           2048
+#define CHANNEL_NUMBER_STR      "Channels: "
+#define PLAYBACK_PROFILE_STR    "Playback:"
+#define CAPTURE_PROFILE_STR     "Capture:"
+#define USB_SIDETONE_GAIN_STR   "usb_sidetone_gain"
+#define ABS_SUB(A, B) (((A) > (B)) ? ((A) - (B)):((B) - (A)))
+#define SAMPLE_RATE_8000          8000
+#define SAMPLE_RATE_11025         11025
+/* TODO: dynamically populate supported sample rates */
+static uint32_t supported_sample_rates[] =
+    {44100, 48000, 64000, 88200, 96000, 176400, 192000, 384000};
+
+#define  MAX_SAMPLE_RATE_SIZE  sizeof(supported_sample_rates)/sizeof(supported_sample_rates[0])
+
+enum usb_usecase_type{
+    USB_PLAYBACK = 0,
+    USB_CAPTURE,
+};
+
+enum {
+    USB_SIDETONE_ENABLE_INDEX = 0,
+    USB_SIDETONE_VOLUME_INDEX,
+    USB_SIDETONE_MAX_INDEX,
+};
+
+struct usb_device_config {
+    struct listnode list;
+    unsigned int bit_width;
+    unsigned int channel_count;
+    unsigned int rate_size;
+    unsigned int rates[MAX_SAMPLE_RATE_SIZE];
+};
+
+struct usb_card_config {
+    struct listnode list;
+    audio_devices_t usb_device_type;
+    int usb_card;
+    struct listnode usb_device_conf_list;
+    struct mixer *usb_snd_mixer;
+    int usb_sidetone_index[USB_SIDETONE_MAX_INDEX];
+    int usb_sidetone_vol_min;
+    int usb_sidetone_vol_max;
+};
+
+struct usb_module {
+    struct listnode usb_card_conf_list;
+    struct audio_device *adev;
+    int sidetone_gain;
+    bool is_capture_supported;
+};
+
+static struct usb_module *usbmod = NULL;
+static bool usb_audio_debug_enable = false;
+static int usb_sidetone_gain = 0;
+
+static const char * const usb_sidetone_enable_str[] = {
+    "Sidetone Playback Switch",
+    "Mic Playback Switch",
+};
+
+static const char * const usb_sidetone_volume_str[] = {
+    "Sidetone Playback Volume",
+    "Mic Playback Volume",
+};
+
+static void usb_mixer_print_enum(struct mixer_ctl *ctl)
+{
+    unsigned int num_enums;
+    unsigned int i;
+    const char *string;
+
+    num_enums = mixer_ctl_get_num_enums(ctl);
+
+    for (i = 0; i < num_enums; i++) {
+        string = mixer_ctl_get_enum_string(ctl, i);
+        ALOGI("\t%s%s", mixer_ctl_get_value(ctl, 0) == (int)i ? ">" : "", string);
+    }
+}
+
+static void usb_soundcard_detail_control(struct mixer *mixer, const char *control)
+{
+    struct mixer_ctl *ctl;
+    enum mixer_ctl_type type;
+    unsigned int num_values;
+    unsigned int i;
+    int min, max;
+
+    if (isdigit(control[0]))
+        ctl = mixer_get_ctl(mixer, atoi(control));
+    else
+        ctl = mixer_get_ctl_by_name(mixer, control);
+
+    if (!ctl) {
+        fprintf(stderr, "Invalid mixer control\n");
+        return;
+    }
+
+    type = mixer_ctl_get_type(ctl);
+    num_values = mixer_ctl_get_num_values(ctl);
+
+    ALOGV("%s:", mixer_ctl_get_name(ctl));
+
+    for (i = 0; i < num_values; i++) {
+        switch (type) {
+            case MIXER_CTL_TYPE_INT:
+                ALOGV(" %d", mixer_ctl_get_value(ctl, i));
+                break;
+            case MIXER_CTL_TYPE_BOOL:
+                ALOGV(" %s", mixer_ctl_get_value(ctl, i) ? "On" : "Off");
+                break;
+            case MIXER_CTL_TYPE_ENUM:
+                usb_mixer_print_enum(ctl);
+                break;
+            case MIXER_CTL_TYPE_BYTE:
+                ALOGV(" 0x%02x", mixer_ctl_get_value(ctl, i));
+                break;
+            default:
+                ALOGV(" unknown");
+                break;
+        }
+    }
+
+    if (type == MIXER_CTL_TYPE_INT) {
+        min = mixer_ctl_get_range_min(ctl);
+        max = mixer_ctl_get_range_max(ctl);
+        ALOGV(" (range %d->%d)", min, max);
+    }
+}
+
+static void usb_soundcard_list_controls(struct mixer *mixer)
+{
+    struct mixer_ctl *ctl;
+    const char *name, *type;
+    unsigned int num_ctls, num_values;
+    unsigned int i;
+
+    num_ctls = mixer_get_num_ctls(mixer);
+
+    ALOGV("Number of controls: %d\n", num_ctls);
+
+    ALOGV("ctl\ttype\tnum\t%-40s value\n", "name");
+    for (i = 0; i < num_ctls; i++) {
+        ctl = mixer_get_ctl(mixer, i);
+        if (ctl != NULL) {
+            name = mixer_ctl_get_name(ctl);
+            type = mixer_ctl_get_type_string(ctl);
+            num_values = mixer_ctl_get_num_values(ctl);
+            ALOGV("%d\t%s\t%d\t%-40s", i, type, num_values, name);
+            if (name != NULL)
+                usb_soundcard_detail_control(mixer, name);
+        }
+    }
+}
+
+static int usb_set_dev_id_mixer_ctl(unsigned int usb_usecase_type, int card,
+                                    char *dev_mixer_ctl_name)
+{
+    struct mixer_ctl *ctl;
+    unsigned int dev_token;
+    const unsigned int pcm_device_number = 0;
+
+    /*
+     * usb_dev_token_id is 32 bit number and is defined as below:
+     * usb_sound_card_idx(31:16) | usb PCM device ID(15:8) | usb_usecase_type(7:0)
+     */
+    dev_token = (card << 16 ) |
+                (pcm_device_number << 8) | (usb_usecase_type & 0xFF);
+
+    ctl = mixer_get_ctl_by_name(usbmod->adev->mixer, dev_mixer_ctl_name);
+    if (!ctl) {
+       ALOGE("%s: Could not get ctl for mixer cmd - %s",
+             __func__, dev_mixer_ctl_name);
+       return -EINVAL;
+    }
+    mixer_ctl_set_value(ctl, 0, dev_token);
+
+    return 0;
+}
+
+static int usb_get_sample_rates(char *rates_str,
+                                struct usb_device_config *config)
+{
+    uint32_t i;
+    char *next_sr_string, *temp_ptr;
+    uint32_t sr, min_sr, max_sr, sr_size = 0;
+
+    /* Sample rate string can be in any of the folloing two bit_widthes:
+     * Rates: 8000 - 48000 (continuous)
+     * Rates: 8000, 44100, 48000
+     * Support both the bit_widths
+     */
+    ALOGV("%s: rates_str %s", __func__, rates_str);
+    next_sr_string = strtok_r(rates_str, "Rates: ", &temp_ptr);
+    if (next_sr_string == NULL) {
+        ALOGE("%s: could not find min rates string", __func__);
+        return -EINVAL;
+    }
+    if (strstr(rates_str, "continuous") != NULL) {
+        min_sr = (uint32_t)atoi(next_sr_string);
+        next_sr_string = strtok_r(NULL, " ,.-", &temp_ptr);
+        if (next_sr_string == NULL) {
+            ALOGE("%s: could not find max rates string", __func__);
+            return -EINVAL;
+        }
+        max_sr = (uint32_t)atoi(next_sr_string);
+
+        for (i = 0; i < MAX_SAMPLE_RATE_SIZE; i++) {
+            if (supported_sample_rates[i] >= min_sr &&
+                supported_sample_rates[i] <= max_sr) {
+                config->rates[sr_size++] = supported_sample_rates[i];
+                ALOGI_IF(usb_audio_debug_enable,
+                    "%s: continuous sample rate supported_sample_rates[%d] %d",
+                    __func__, i, supported_sample_rates[i]);
+            }
+        }
+    } else {
+        do {
+            sr = (uint32_t)atoi(next_sr_string);
+            for (i = 0; i < MAX_SAMPLE_RATE_SIZE; i++) {
+                if (supported_sample_rates[i] == sr) {
+                    ALOGI_IF(usb_audio_debug_enable,
+                        "%s: sr %d, supported_sample_rates[%d] %d -> matches!!",
+                        __func__, sr, i, supported_sample_rates[i]);
+                    config->rates[sr_size++] = supported_sample_rates[i];
+                }
+            }
+            next_sr_string = strtok_r(NULL, " ,.-", &temp_ptr);
+        } while (next_sr_string != NULL);
+    }
+    config->rate_size = sr_size;
+    return 0;
+}
+
+static int usb_get_capability(int type,
+                              struct usb_card_config *usb_card_info,
+                              int card)
+{
+    int32_t size = 0;
+    int32_t fd=-1;
+    int32_t channels_no;
+    char *str_start = NULL;
+    char *str_end = NULL;
+    char *channel_start = NULL;
+    char *bit_width_start = NULL;
+    char *rates_str_start = NULL;
+    char *target = NULL;
+    char *read_buf = NULL;
+    char *rates_str = NULL;
+    char path[128];
+    int ret = 0;
+    char *bit_width_str = NULL;
+    struct usb_device_config * usb_device_info;
+    bool check = false;
+
+    memset(path, 0, sizeof(path));
+    ALOGV("%s: for %s", __func__, (type == USB_PLAYBACK) ?
+          PLAYBACK_PROFILE_STR : CAPTURE_PROFILE_STR);
+
+    /* TODO: convert the below to using alsa_utils */
+    ret = snprintf(path, sizeof(path), "/proc/asound/card%u/stream0",
+             card);
+    if(ret < 0) {
+        ALOGE("%s: failed on snprintf (%d) to path %s\n",
+          __func__, ret, path);
+        goto done;
+    }
+
+    fd = open(path, O_RDONLY);
+    if (fd <0) {
+        ALOGE("%s: error failed to open config file %s error: %d\n",
+              __func__, path, errno);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    read_buf = (char *)calloc(1, USB_BUFF_SIZE + 1);
+
+    if (!read_buf) {
+        ALOGE("Failed to create read_buf");
+        ret = -ENOMEM;
+        goto done;
+    }
+
+    if(read(fd, read_buf, USB_BUFF_SIZE) < 0) {
+        ALOGE("file read error\n");
+        goto done;
+    }
+    str_start = strstr(read_buf, ((type == USB_PLAYBACK) ?
+                       PLAYBACK_PROFILE_STR : CAPTURE_PROFILE_STR));
+    if (str_start == NULL) {
+        ALOGE("%s: error %s section not found in usb config file",
+               __func__, ((type == USB_PLAYBACK) ?
+               PLAYBACK_PROFILE_STR : CAPTURE_PROFILE_STR));
+        ret = -EINVAL;
+        goto done;
+    }
+    str_end = strstr(read_buf, ((type == USB_PLAYBACK) ?
+                       CAPTURE_PROFILE_STR : PLAYBACK_PROFILE_STR));
+    if (str_end > str_start)
+        check = true;
+
+    ALOGV("%s: usb_config = %s, check %d\n", __func__, str_start, check);
+
+    while (str_start != NULL) {
+        str_start = strstr(str_start, "Altset");
+        if ((str_start == NULL) || (check  && (str_start >= str_end))) {
+            ALOGV("%s: done parsing %s\n", __func__, str_start);
+            break;
+        }
+        ALOGV("%s: remaining string %s\n", __func__, str_start);
+        str_start += sizeof("Altset");
+        usb_device_info = calloc(1, sizeof(struct usb_device_config));
+        if (usb_device_info == NULL) {
+            ALOGE("%s: error unable to allocate memory",
+                  __func__);
+            ret = -ENOMEM;
+            break;
+        }
+        /* Bit bit_width parsing */
+        bit_width_start = strstr(str_start, "Format: ");
+        if (bit_width_start == NULL) {
+            ALOGI("%s: Could not find bit_width string", __func__);
+            free(usb_device_info);
+            continue;
+        }
+        target = strchr(bit_width_start, '\n');
+        if (target == NULL) {
+            ALOGI("%s:end of line not found", __func__);
+            free(usb_device_info);
+            continue;
+        }
+        size = target - bit_width_start;
+        if ((bit_width_str = (char *)malloc(size + 1)) == NULL) {
+            ALOGE("%s: unable to allocate memory to hold bit width strings",
+                  __func__);
+            ret = -EINVAL;
+            free(usb_device_info);
+            break;
+        }
+        memcpy(bit_width_str, bit_width_start, size);
+        bit_width_str[size] = '\0';
+        if (strstr(bit_width_str, "S16_LE"))
+            usb_device_info->bit_width = 16;
+        else if (strstr(bit_width_str, "S24_LE"))
+            usb_device_info->bit_width = 24;
+        else if (strstr(bit_width_str, "S24_3LE"))
+            usb_device_info->bit_width = 24;
+        else if (strstr(bit_width_str, "S32_LE"))
+            usb_device_info->bit_width = 32;
+
+        if (bit_width_str)
+            free(bit_width_str);
+
+        /* channels parsing */
+        channel_start = strstr(str_start, CHANNEL_NUMBER_STR);
+        if (channel_start == NULL) {
+            ALOGI("%s: could not find Channels string", __func__);
+            free(usb_device_info);
+            continue;
+        }
+        channels_no = atoi(channel_start + strlen(CHANNEL_NUMBER_STR));
+        usb_device_info->channel_count =  channels_no;
+
+        /* Sample rates parsing */
+        rates_str_start = strstr(str_start, "Rates: ");
+        if (rates_str_start == NULL) {
+            ALOGI("%s: cant find rates string", __func__);
+            free(usb_device_info);
+            continue;
+        }
+        target = strchr(rates_str_start, '\n');
+        if (target == NULL) {
+            ALOGI("%s: end of line not found", __func__);
+            free(usb_device_info);
+            continue;
+        }
+        size = target - rates_str_start;
+        if ((rates_str = (char *)malloc(size + 1)) == NULL) {
+            ALOGE("%s: unable to allocate memory to hold sample rate strings",
+                  __func__);
+            ret = -EINVAL;
+            free(usb_device_info);
+            break;
+        }
+        memcpy(rates_str, rates_str_start, size);
+        rates_str[size] = '\0';
+        ret = usb_get_sample_rates(rates_str, usb_device_info);
+        if (rates_str)
+            free(rates_str);
+        if (ret < 0) {
+            ALOGE("%s: error unable to get sample rate values",
+                  __func__);
+            free(usb_device_info);
+            continue;
+        }
+        /* Add to list if every field is valid */
+        list_add_tail(&usb_card_info->usb_device_conf_list,
+                      &usb_device_info->list);
+    }
+
+done:
+    if (fd >= 0) close(fd);
+    if (read_buf) free(read_buf);
+    return ret;
+}
+
+static int usb_get_device_playback_config(struct usb_card_config *usb_card_info,
+                                    int card)
+{
+    int ret;
+
+    /* get capabilities */
+    if ((ret = usb_get_capability(USB_PLAYBACK, usb_card_info, card))) {
+        ALOGE("%s: could not get Playback capabilities from usb device",
+               __func__);
+        goto exit;
+    }
+    usb_set_dev_id_mixer_ctl(USB_PLAYBACK, card, "USB_AUDIO_RX dev_token");
+
+exit:
+
+    return ret;
+}
+
+static int usb_get_device_capture_config(struct usb_card_config *usb_card_info,
+                                      int card)
+{
+    int ret;
+
+    /* get capabilities */
+    if ((ret = usb_get_capability(USB_CAPTURE, usb_card_info, card))) {
+        ALOGE("%s: could not get Playback capabilities from usb device",
+               __func__);
+        goto exit;
+    }
+    usb_set_dev_id_mixer_ctl(USB_CAPTURE, card, "USB_AUDIO_TX dev_token");
+
+exit:
+    return ret;
+}
+
+static void usb_get_sidetone_mixer(struct usb_card_config *usb_card_info)
+{
+    struct mixer_ctl *ctl;
+    unsigned int index;
+
+    for (index = 0; index < USB_SIDETONE_MAX_INDEX; index++)
+        usb_card_info->usb_sidetone_index[index] = -1;
+
+    usb_card_info->usb_snd_mixer = mixer_open(usb_card_info->usb_card);
+    for (index = 0;
+         index < sizeof(usb_sidetone_enable_str)/sizeof(usb_sidetone_enable_str[0]);
+         index++) {
+        ctl = mixer_get_ctl_by_name(usb_card_info->usb_snd_mixer,
+                                    usb_sidetone_enable_str[index]);
+        if (ctl) {
+            usb_card_info->usb_sidetone_index[USB_SIDETONE_ENABLE_INDEX] = index;
+            /* Disable device sidetone by default */
+            mixer_ctl_set_value(ctl, 0, false);
+            break;
+        }
+    }
+    for (index = 0;
+         index < sizeof(usb_sidetone_volume_str)/sizeof(usb_sidetone_volume_str[0]);
+         index++) {
+        ctl = mixer_get_ctl_by_name(usb_card_info->usb_snd_mixer,
+                                    usb_sidetone_volume_str[index]);
+        if (ctl) {
+            usb_card_info->usb_sidetone_index[USB_SIDETONE_VOLUME_INDEX] = index;
+            usb_card_info->usb_sidetone_vol_min = mixer_ctl_get_range_min(ctl);
+            usb_card_info->usb_sidetone_vol_max = mixer_ctl_get_range_max(ctl);
+            break;
+        }
+    }
+
+    if ((usb_card_info->usb_snd_mixer != NULL) && (usb_audio_debug_enable))
+        usb_soundcard_list_controls(usb_card_info->usb_snd_mixer);
+
+    return;
+}
+
+static bool usb_valid_device(audio_devices_t device)
+{
+    if ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_USB_DEVICE))
+        return true;
+
+    if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
+        device &= ~AUDIO_DEVICE_BIT_IN;
+        if (popcount(device) == 1 && (device & AUDIO_DEVICE_IN_USB_DEVICE) != 0)
+            return true;
+    }
+
+    return false;
+}
+
+static void usb_print_active_device(void){
+    struct listnode *node_i, *node_j;
+    struct usb_device_config *dev_info;
+    struct usb_card_config *card_info;
+    unsigned int i;
+
+    ALOGI("%s", __func__);
+    list_for_each(node_i, &usbmod->usb_card_conf_list) {
+        card_info = node_to_item(node_i, struct usb_card_config, list);
+        ALOGI("%s: card_dev_type (0x%x), card_no(%d)",
+               __func__,  card_info->usb_device_type, card_info->usb_card);
+        list_for_each(node_j, &card_info->usb_device_conf_list) {
+            dev_info = node_to_item(node_j, struct usb_device_config, list);
+            ALOGI("%s: bit-width(%d) channel(%d)",
+                   __func__, dev_info->bit_width, dev_info->channel_count);
+            for (i =  0; i < dev_info->rate_size; i++)
+                ALOGI("%s: rate %d", __func__, dev_info->rates[i]);
+        }
+    }
+}
+
+static bool usb_get_best_match_for_bit_width(
+                            struct listnode *dev_list,
+                            unsigned int stream_bit_width,
+                            unsigned int *bit_width)
+{
+    struct listnode *node_i;
+    struct usb_device_config *dev_info;
+    unsigned int candidate = 0;
+
+    list_for_each(node_i, dev_list) {
+        dev_info = node_to_item(node_i, struct usb_device_config, list);
+        ALOGI_IF(usb_audio_debug_enable,
+                 "%s: USB bw(%d), stream bw(%d), candidate(%d)",
+                 __func__, dev_info->bit_width,
+                 stream_bit_width, candidate);
+        if (dev_info->bit_width == stream_bit_width) {
+            *bit_width = dev_info->bit_width;
+            ALOGV("%s: Found match bit-width (%d)",
+                  __func__, dev_info->bit_width);
+            goto exit;
+        } else if (candidate == 0) {
+                candidate = dev_info->bit_width;
+        }
+        /*
+        * If stream bit is 24, USB supports both 16 bit and 32 bit, then
+        *  higher bit width 32 is picked up instead of 16-bit
+        */
+        else if (ABS_SUB(stream_bit_width, dev_info->bit_width) <
+                 ABS_SUB(stream_bit_width, candidate)) {
+            candidate = dev_info->bit_width;
+        }
+        else if ((ABS_SUB(stream_bit_width, dev_info->bit_width) ==
+                  ABS_SUB(stream_bit_width, candidate)) &&
+                 (dev_info->bit_width > candidate)) {
+            candidate = dev_info->bit_width;
+        }
+    }
+    ALOGV("%s: No match found, use the best candidate bw(%d)",
+          __func__, candidate);
+    *bit_width = candidate;
+exit:
+    return true;
+}
+
+static bool usb_get_best_match_for_channels(
+                            struct listnode *dev_list,
+                            unsigned int bit_width,
+                            unsigned int stream_ch,
+                            unsigned int *channel_count)
+{
+    struct listnode *node_i;
+    struct usb_device_config *dev_info;
+    unsigned int candidate = 0;
+
+    list_for_each(node_i, dev_list) {
+        dev_info = node_to_item(node_i, struct usb_device_config, list);
+        ALOGI_IF(usb_audio_debug_enable,
+                 "%s: USB ch(%d)bw(%d), stream ch(%d)bw(%d), candidate(%d)",
+                 __func__, dev_info->channel_count, dev_info->bit_width,
+                 stream_ch, bit_width, candidate);
+        if (dev_info->bit_width != bit_width)
+            continue;
+        if (dev_info->channel_count== stream_ch) {
+            *channel_count = dev_info->channel_count;
+            ALOGV("%s: Found match channels (%d)",
+                  __func__, dev_info->channel_count);
+            goto exit;
+        } else if (candidate == 0)
+                candidate = dev_info->channel_count;
+            /*
+            * If stream channel is 4, USB supports both 3 and 5, then
+            *  higher channel 5 is picked up instead of 3
+            */
+        else if (ABS_SUB(stream_ch, dev_info->channel_count) <
+                 ABS_SUB(stream_ch, candidate)) {
+            candidate = dev_info->channel_count;
+        } else if ((ABS_SUB(stream_ch, dev_info->channel_count) ==
+                    ABS_SUB(stream_ch, candidate)) &&
+                   (dev_info->channel_count > candidate)) {
+            candidate = dev_info->channel_count;
+        }
+    }
+    ALOGV("%s: No match found, use the best candidate ch(%d)",
+          __func__, candidate);
+    *channel_count = candidate;
+exit:
+    return true;
+
+}
+
+static bool usb_sample_rate_multiple(
+                                     unsigned int stream_sample_rate,
+                                     unsigned int base)
+{
+    return (((stream_sample_rate / base) * base) == stream_sample_rate);
+}
+
+static bool usb_find_sample_rate_candidate(unsigned int base,
+                                           unsigned stream_rate,
+                                           unsigned int usb_rate,
+                                           unsigned int cur_candidate,
+                                           unsigned int *update_candidate)
+{
+    /* For sample rate, we should consider  fracational sample rate as high priority.
+    * For example, if the stream is 88.2kHz and USB device support both 44.1kH and
+    * 48kHz sample rate, we should pick 44.1kHz instead of 48kHz
+    */
+    if (!usb_sample_rate_multiple(cur_candidate, base) &&
+       usb_sample_rate_multiple(usb_rate, base)) {
+        *update_candidate = usb_rate;
+    } else if (usb_sample_rate_multiple(cur_candidate, base) &&
+               usb_sample_rate_multiple(usb_rate, base)) {
+        if (ABS_SUB(stream_rate, usb_rate) <
+            ABS_SUB(stream_rate, cur_candidate)) {
+            *update_candidate = usb_rate;
+        } else if ((ABS_SUB(stream_rate, usb_rate) ==
+                    ABS_SUB(stream_rate, cur_candidate)) &&
+                   (usb_rate > cur_candidate)) {
+            *update_candidate = usb_rate;
+        }
+    } else if (!usb_sample_rate_multiple(cur_candidate, base) &&
+               !usb_sample_rate_multiple(usb_rate, base)) {
+        if (ABS_SUB(stream_rate, usb_rate) <
+            ABS_SUB(stream_rate, cur_candidate)) {
+            *update_candidate = usb_rate;
+        } else if ((ABS_SUB(stream_rate, usb_rate) ==
+                    ABS_SUB(stream_rate, cur_candidate)) &&
+                   (usb_rate > cur_candidate)) {
+            *update_candidate = usb_rate;
+        }
+    }
+    return true;
+}
+
+static bool usb_get_best_match_for_sample_rate(
+                            struct listnode *dev_list,
+                            unsigned int bit_width,
+                            unsigned int channel_count,
+                            unsigned int stream_sample_rate,
+                            unsigned int *sr)
+{
+    struct listnode *node_i;
+    struct usb_device_config *dev_info;
+    unsigned int candidate = 48000;
+    unsigned int base = SAMPLE_RATE_8000;
+    bool multiple_8k = usb_sample_rate_multiple(stream_sample_rate, base);
+    unsigned int i;
+
+    ALOGV("%s: stm ch(%d)bw(%d)sr(%d), stream sample multiple of 8kHz(%d)",
+        __func__, channel_count, bit_width, stream_sample_rate, multiple_8k);
+
+    list_for_each(node_i, dev_list) {
+        dev_info = node_to_item(node_i, struct usb_device_config, list);
+        ALOGI_IF(usb_audio_debug_enable,
+                 "%s: USB ch(%d)bw(%d), stm ch(%d)bw(%d)sr(%d), candidate(%d)",
+                 __func__, dev_info->channel_count, dev_info->bit_width,
+                 channel_count, bit_width, stream_sample_rate, candidate);
+        if ((dev_info->bit_width != bit_width) || dev_info->channel_count != channel_count)
+            continue;
+
+        candidate = 0;
+        for (i = 0; i < dev_info->rate_size; i++) {
+            ALOGI_IF(usb_audio_debug_enable,
+                     "%s: USB ch(%d)bw(%d)sr(%d), stm ch(%d)bw(%d)sr(%d), candidate(%d)",
+                     __func__, dev_info->channel_count,
+                     dev_info->bit_width, dev_info->rates[i],
+                     channel_count, bit_width, stream_sample_rate, candidate);
+            if (stream_sample_rate == dev_info->rates[i]) {
+                *sr = dev_info->rates[i];
+                ALOGV("%s: Found match sample rate (%d)",
+                      __func__, dev_info->rates[i]);
+                goto exit;
+            } else if (candidate == 0) {
+                    candidate = dev_info->rates[i];
+                /*
+                * For sample rate, we should consider  fracational sample rate as high priority.
+                * For example, if the stream is 88.2kHz and USB device support both 44.1kH and
+                * 48kHz sample rate, we should pick 44.1kHz instead of 48kHz
+                */
+            } else if (multiple_8k) {
+                usb_find_sample_rate_candidate(SAMPLE_RATE_8000,
+                                               stream_sample_rate,
+                                               dev_info->rates[i],
+                                               candidate,
+                                               &candidate);
+            } else {
+                usb_find_sample_rate_candidate(SAMPLE_RATE_11025,
+                                               stream_sample_rate,
+                                               dev_info->rates[i],
+                                               candidate,
+                                               &candidate);
+            }
+        }
+    }
+    ALOGV("%s: No match found, use the best candidate sr(%d)",
+          __func__, candidate);
+    *sr = candidate;
+exit:
+    return true;
+}
+
+static bool usb_audio_backend_apply_policy(struct listnode *dev_list,
+                                           unsigned int *bit_width,
+                                           unsigned int *sample_rate,
+                                           unsigned int *channel_count)
+{
+    ALOGV("%s: from stream: bit-width(%d) sample_rate(%d) channels (%d)",
+           __func__, *bit_width, *sample_rate, *channel_count);
+    if (list_empty(dev_list)) {
+        *sample_rate = 48000;
+        *bit_width = 16;
+        *channel_count = 2;
+        ALOGE("%s: list is empty,fall back to default setting", __func__);
+        goto exit;
+    }
+    usb_get_best_match_for_bit_width(dev_list, *bit_width, bit_width);
+    usb_get_best_match_for_channels(dev_list,
+                                    *bit_width,
+                                    *channel_count,
+                                    channel_count);
+    usb_get_best_match_for_sample_rate(dev_list,
+                                       *bit_width,
+                                       *channel_count,
+                                       *sample_rate,
+                                       sample_rate);
+exit:
+    ALOGV("%s: Updated sample rate per profile: bit-width(%d) rate(%d) chs(%d)",
+           __func__, *bit_width, *sample_rate, *channel_count);
+    return true;
+}
+
+static int usb_get_sidetone_gain(struct usb_card_config *card_info)
+{
+    int gain = card_info->usb_sidetone_vol_min + usbmod->sidetone_gain;
+    if (gain > card_info->usb_sidetone_vol_max)
+        gain = card_info->usb_sidetone_vol_max;
+    return gain;
+}
+
+void audio_extn_usb_set_sidetone_gain(struct str_parms *parms,
+                                char *value, int len)
+{
+    int err;
+
+    err = str_parms_get_str(parms, USB_SIDETONE_GAIN_STR,
+                            value, len);
+    if (err >= 0) {
+        usb_sidetone_gain = pow(10.0, (float)(atoi(value))/10.0);
+        ALOGV("%s: sidetone gain(%s) decimal %d",
+              __func__, value, usb_sidetone_gain);
+        str_parms_del(parms, USB_SIDETONE_GAIN_STR);
+    }
+    return;
+}
+
+int audio_extn_usb_enable_sidetone(int device, bool enable)
+{
+    int ret = -ENODEV;
+    struct listnode *node_i;
+    struct usb_card_config *card_info;
+    int i;
+    ALOGV("%s: card_dev_type (0x%x), sidetone enable(%d)",
+           __func__,  device, enable);
+
+    list_for_each(node_i, &usbmod->usb_card_conf_list) {
+        card_info = node_to_item(node_i, struct usb_card_config, list);
+        ALOGV("%s: card_dev_type (0x%x), card_no(%d)",
+               __func__,  card_info->usb_device_type, card_info->usb_card);
+        if (card_info->usb_device_type == AUDIO_DEVICE_OUT_USB_DEVICE) {
+            if ((i = card_info->usb_sidetone_index[USB_SIDETONE_ENABLE_INDEX]) != -1) {
+                struct mixer_ctl *ctl = mixer_get_ctl_by_name(
+                                card_info->usb_snd_mixer,
+                                usb_sidetone_enable_str[i]);
+                if (ctl)
+                    mixer_ctl_set_value(ctl, 0, enable);
+                else
+                    break;
+
+                if ((i = card_info->usb_sidetone_index[USB_SIDETONE_VOLUME_INDEX]) != -1) {
+                    ctl = mixer_get_ctl_by_name(
+                                card_info->usb_snd_mixer,
+                                usb_sidetone_volume_str[i]);
+                    if (ctl == NULL)
+                        ALOGV("%s: sidetone gain mixer command is not found",
+                               __func__);
+                    else if (enable)
+                        mixer_ctl_set_value(ctl, 0,
+                                            usb_get_sidetone_gain(card_info));
+                }
+                ret = 0;
+                break;
+            }
+        }
+    }
+    return ret;
+}
+
+bool audio_extn_usb_is_config_supported(unsigned int *bit_width,
+                                        unsigned int *sample_rate,
+                                        unsigned int *channel_count,
+                                        bool is_playback)
+{
+    struct listnode *node_i;
+    struct usb_card_config *card_info;
+
+    ALOGV("%s: from stream: bit-width(%d) sample_rate(%d) ch(%d) is_playback(%d)",
+           __func__, *bit_width, *sample_rate, *channel_count, is_playback);
+    list_for_each(node_i, &usbmod->usb_card_conf_list) {
+        card_info = node_to_item(node_i, struct usb_card_config, list);
+        ALOGI_IF(usb_audio_debug_enable,
+                 "%s: card_dev_type (0x%x), card_no(%d)",
+                 __func__,  card_info->usb_device_type, card_info->usb_card);
+        /* Currently only apply the first playback sound card configuration */
+        if ((is_playback && card_info->usb_device_type == AUDIO_DEVICE_OUT_USB_DEVICE) ||
+            ((!is_playback) && card_info->usb_device_type == AUDIO_DEVICE_IN_USB_DEVICE)){
+            usb_audio_backend_apply_policy(&card_info->usb_device_conf_list,
+                                           bit_width,
+                                           sample_rate,
+                                           channel_count);
+            break;
+        }
+    }
+    ALOGV("%s: updated: bit-width(%d) sample_rate(%d) channels (%d)",
+           __func__, *bit_width, *sample_rate, *channel_count);
+
+    return true;
+}
+
+bool audio_extn_usb_is_capture_supported()
+{
+    if (usbmod == NULL) {
+        ALOGE("%s: USB device object is NULL", __func__);
+        return false;
+    }
+    ALOGV("%s: capture_supported %d",__func__,usbmod->is_capture_supported);
+    return usbmod->is_capture_supported;
+}
+
+void audio_extn_usb_add_device(audio_devices_t device, int card)
+{
+    struct usb_card_config *usb_card_info;
+    char check_debug_enable[PROPERTY_VALUE_MAX];
+    struct listnode *node_i;
+
+    property_get("audio.usb.enable.debug", check_debug_enable, NULL);
+    if (atoi(check_debug_enable)) {
+        usb_audio_debug_enable = true;
+    }
+
+    ALOGI_IF(usb_audio_debug_enable,
+             "%s: parameters device(0x%x), card(%d)",
+             __func__, device, card);
+    if (usbmod == NULL) {
+        ALOGE("%s: USB device object is NULL", __func__);
+        goto exit;
+    }
+
+    if (!(usb_valid_device(device)) || (card < 0)) {
+        ALOGE("%s:device(0x%x), card(%d)",
+              __func__, device, card);
+        goto exit;
+    }
+
+    list_for_each(node_i, &usbmod->usb_card_conf_list) {
+        usb_card_info = node_to_item(node_i, struct usb_card_config, list);
+        ALOGI_IF(usb_audio_debug_enable,
+                 "%s: list has capability for card_dev_type (0x%x), card_no(%d)",
+                 __func__,  usb_card_info->usb_device_type, usb_card_info->usb_card);
+        /* If we have cached the capability */
+        if ((usb_card_info->usb_device_type == device) && (usb_card_info->usb_card == card)) {
+            ALOGV("%s: capability for device(0x%x), card(%d) is cached, no need to update",
+                  __func__, device, card);
+            goto exit;
+        }
+    }
+    usb_card_info = calloc(1, sizeof(struct usb_card_config));
+    if (usb_card_info == NULL) {
+        ALOGE("%s: error unable to allocate memory",
+              __func__);
+        goto exit;
+    }
+    list_init(&usb_card_info->usb_device_conf_list);
+    if (device & AUDIO_DEVICE_OUT_USB_DEVICE) {
+        if (!usb_get_device_playback_config(usb_card_info, card)){
+            usb_card_info->usb_card = card;
+            usb_card_info->usb_device_type = AUDIO_DEVICE_OUT_USB_DEVICE;
+            usb_get_sidetone_mixer(usb_card_info);
+            list_add_tail(&usbmod->usb_card_conf_list, &usb_card_info->list);
+            goto exit;
+        }
+    } else if (device & AUDIO_DEVICE_IN_USB_DEVICE) {
+        if (!usb_get_device_capture_config(usb_card_info, card)) {
+            usb_card_info->usb_card = card;
+            usb_card_info->usb_device_type = AUDIO_DEVICE_IN_USB_DEVICE;
+            usbmod->is_capture_supported = true;
+            list_add_tail(&usbmod->usb_card_conf_list, &usb_card_info->list);
+            goto exit;
+        }
+    }
+    /* free memory in error case */
+    if (usb_card_info != NULL)
+        free(usb_card_info);
+exit:
+    if (usb_audio_debug_enable)
+        usb_print_active_device();
+    return;
+}
+
+void audio_extn_usb_remove_device(audio_devices_t device, int card)
+{
+    struct listnode *node_i, *temp_i;
+    struct listnode *node_j, *temp_j;
+    struct usb_device_config *dev_info;
+    struct usb_card_config *card_info;
+    unsigned int i;
+
+    ALOGV("%s: device(0x%x), card(%d)",
+           __func__, device, card);
+
+    if (usbmod == NULL) {
+        ALOGE("%s: USB device object is NULL", __func__);
+        goto exit;
+    }
+
+    if (!(usb_valid_device(device)) || (card < 0)) {
+        ALOGE("%s: Invalid parameters device(0x%x), card(%d)",
+              __func__, device, card);
+        goto exit;
+    }
+    list_for_each_safe(node_i, temp_i, &usbmod->usb_card_conf_list) {
+        card_info = node_to_item(node_i, struct usb_card_config, list);
+        ALOGV("%s: card_dev_type (0x%x), card_no(%d)",
+               __func__,  card_info->usb_device_type, card_info->usb_card);
+        if ((device == card_info->usb_device_type) && (card == card_info->usb_card)){
+            list_for_each_safe(node_j, temp_j, &card_info->usb_device_conf_list) {
+                dev_info = node_to_item(node_j, struct usb_device_config, list);
+                ALOGV("%s: bit-width(%d) channel(%d)",
+                       __func__, dev_info->bit_width, dev_info->channel_count);
+                for (i =  0; i < dev_info->rate_size; i++)
+                    ALOGV("%s: rate %d", __func__, dev_info->rates[i]);
+
+                list_remove(node_j);
+                free(node_to_item(node_j, struct usb_device_config, list));
+            }
+            list_remove(node_i);
+            free(node_to_item(node_i, struct usb_card_config, list));
+        }
+    }
+    usbmod->is_capture_supported = false;
+exit:
+    if (usb_audio_debug_enable)
+        usb_print_active_device();
+
+    return;
+}
+
+void audio_extn_usb_init(void *adev)
+{
+    if (usbmod == NULL) {
+        usbmod = calloc(1, sizeof(struct usb_module));
+        if (usbmod == NULL) {
+            ALOGE("%s: error unable to allocate memory", __func__);
+            goto exit;
+        }
+    } else {
+        memset(usbmod, 0, sizeof(*usbmod));
+    }
+
+    list_init(&usbmod->usb_card_conf_list);
+    usbmod->adev = (struct audio_device*)adev;
+    usbmod->sidetone_gain = usb_sidetone_gain;
+    usbmod->is_capture_supported = false;
+exit:
+    return;
+}
+
+void audio_extn_usb_deinit(void)
+{
+    if (NULL != usbmod){
+        free(usbmod);
+        usbmod = NULL;
+    }
+}
+#endif /*USB_HEADSET_ENABLED end*/
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 85216bc..4af1e9c 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -855,6 +855,8 @@
     bool switch_device[AUDIO_USECASE_MAX];
     int i, num_uc_to_switch = 0;
 
+    platform_check_and_set_playback_backend_cfg(adev, uc_info, snd_device);
+
     /*
      * This function is to make sure that all the usecases that are active on
      * the hardware codec backend are always routed to any one device that is
@@ -1199,7 +1201,8 @@
 
     /* Enable new sound devices */
     if (out_snd_device != SND_DEVICE_NONE) {
-        if (usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND)
+        if ((usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) ||
+            (usecase->devices & AUDIO_DEVICE_OUT_USB_DEVICE))
             check_and_route_playback_usecases(adev, usecase, out_snd_device);
         enable_snd_device(adev, out_snd_device);
     }
@@ -3555,6 +3558,43 @@
         adev->bt_wb_speech_enabled = !strcmp(value, AUDIO_PARAMETER_VALUE_ON);
     }
 
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, value, sizeof(value));
+    if (ret >= 0) {
+        audio_devices_t device = (audio_devices_t)strtoul(value, NULL, 10);
+        if (device == AUDIO_DEVICE_OUT_USB_DEVICE) {
+            ret = str_parms_get_str(parms, "card", value, sizeof(value));
+            if (ret >= 0) {
+                const int card = atoi(value);
+                audio_extn_usb_add_device(AUDIO_DEVICE_OUT_USB_DEVICE, card);
+            }
+        } else if (device == AUDIO_DEVICE_IN_USB_DEVICE) {
+            ret = str_parms_get_str(parms, "card", value, sizeof(value));
+            if (ret >= 0) {
+                const int card = atoi(value);
+                audio_extn_usb_add_device(AUDIO_DEVICE_IN_USB_DEVICE, card);
+            }
+        }
+    }
+
+    ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, value, sizeof(value));
+    if (ret >= 0) {
+        audio_devices_t device = (audio_devices_t)strtoul(value, NULL, 10);
+        if (device == AUDIO_DEVICE_OUT_USB_DEVICE) {
+            ret = str_parms_get_str(parms, "card", value, sizeof(value));
+            if (ret >= 0) {
+                const int card = atoi(value);
+
+                audio_extn_usb_remove_device(AUDIO_DEVICE_OUT_USB_DEVICE, card);
+            }
+        } else if (device == AUDIO_DEVICE_IN_USB_DEVICE) {
+            ret = str_parms_get_str(parms, "card", value, sizeof(value));
+            if (ret >= 0) {
+                const int card = atoi(value);
+                audio_extn_usb_remove_device(AUDIO_DEVICE_IN_USB_DEVICE, card);
+            }
+        }
+    }
+
     audio_extn_hfp_set_parameters(adev, parms);
 done:
     str_parms_destroy(parms);
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index b0a6282..35b4bdd 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -49,6 +49,8 @@
 #define ACDB_DEV_TYPE_IN 2
 
 #define MAX_SUPPORTED_CHANNEL_MASKS 2
+#define MAX_SUPPORTED_FORMATS 15
+#define MAX_SUPPORTED_SAMPLE_RATES 7
 #define DEFAULT_HDMI_OUT_CHANNELS   2
 
 #define ERROR_LOG_ENTRIES 16
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index f7953cc..65600ee 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -1093,6 +1093,13 @@
     return 0;
 }
 
+bool platform_check_and_set_playback_backend_cfg(struct audio_device* adev __unused,
+                                              struct audio_usecase *usecase __unused,
+                                              snd_device_t snd_device __unused)
+{
+    return false;
+}
+
 bool platform_check_and_set_capture_backend_cfg(struct audio_device* adev __unused,
                                               struct audio_usecase *usecase __unused,
                                               snd_device_t snd_device __unused)
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index eafb64a..072a1e4 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -1104,6 +1104,13 @@
     return 0;
 }
 
+bool platform_check_and_set_playback_backend_cfg(struct audio_device* adev __unused,
+                                              struct audio_usecase *usecase __unused,
+                                              snd_device_t snd_device __unused)
+{
+    return false;
+}
+
 bool platform_check_and_set_capture_backend_cfg(struct audio_device* adev __unused,
                                               struct audio_usecase *usecase __unused)
 {
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 3deac03..9c81f97 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -138,6 +138,7 @@
     struct csd_data *csd;
     char ec_ref_mixer_path[64];
 
+    codec_backend_cfg_t current_backend_cfg[MAX_CODEC_BACKENDS];
     char *snd_card_name;
     int max_vol_index;
     int max_mic_count;
@@ -227,6 +228,9 @@
     [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = "voice-tty-vco-headphones",
     [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = "voice-tty-hco-handset",
     [SND_DEVICE_OUT_VOICE_TX] = "voice-tx",
+    [SND_DEVICE_OUT_USB_HEADSET] = "usb-headset",
+    [SND_DEVICE_OUT_USB_HEADPHONES] = "usb-headphones",
+    [SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = "speaker-and-usb-headphones",
     [SND_DEVICE_OUT_SPEAKER_PROTECTED] = "speaker-protected",
     [SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = "voice-speaker-protected",
     [SND_DEVICE_OUT_VOICE_SPEAKER_HFP] = "voice-speaker-hfp",
@@ -278,6 +282,7 @@
     [SND_DEVICE_IN_VOICE_REC_MIC_AEC_NS] = "voice-rec-mic",
     [SND_DEVICE_IN_VOICE_REC_DMIC_STEREO] = "voice-rec-dmic-ef",
     [SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE] = "voice-rec-dmic-ef-fluence",
+    [SND_DEVICE_IN_USB_HEADSET_MIC] = "usb-headset-mic",
     [SND_DEVICE_IN_VOICE_REC_HEADSET_MIC] = "headset-mic",
 
     [SND_DEVICE_IN_UNPROCESSED_MIC] = "unprocessed-mic",
@@ -324,6 +329,9 @@
     [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17,
     [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = 37,
     [SND_DEVICE_OUT_VOICE_TX] = 45,
+    [SND_DEVICE_OUT_USB_HEADSET] = 45,
+    [SND_DEVICE_OUT_USB_HEADPHONES] = 45,
+    [SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = 14,
     [SND_DEVICE_OUT_SPEAKER_PROTECTED] = 124,
     [SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = 101,
     [SND_DEVICE_OUT_VOICE_SPEAKER_HFP] = ACDB_ID_VOICE_SPEAKER,
@@ -383,7 +391,7 @@
     [SND_DEVICE_IN_UNPROCESSED_QUAD_MIC] = 125,
 
     [SND_DEVICE_IN_VOICE_RX] = 44,
-
+    [SND_DEVICE_IN_USB_HEADSET_MIC] = 44,
     [SND_DEVICE_IN_THREE_MIC] = 46,
     [SND_DEVICE_IN_QUAD_MIC] = 46,
     [SND_DEVICE_IN_CAPTURE_VI_FEEDBACK] = 102,
@@ -393,6 +401,9 @@
     [SND_DEVICE_IN_HANDSET_QMIC_AEC] = 125, /* override this for new target to 140 */
 };
 
+// Platform specific backend bit width table
+static int backend_bit_width_table[SND_DEVICE_MAX] = {0};
+
 struct name_to_index {
     char name[100];
     unsigned int index;
@@ -427,6 +438,9 @@
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_USB_HEADSET)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_USB_HEADPHONES)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET)},
 
     /* in */
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_PROTECTED)},
@@ -478,6 +492,7 @@
     {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_REC_DMIC_STEREO)},
     {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_REC_DMIC_FLUENCE)},
     {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_REC_HEADSET_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_USB_HEADSET_MIC)},
 
     {TO_NAME_INDEX(SND_DEVICE_IN_UNPROCESSED_MIC)},
     {TO_NAME_INDEX(SND_DEVICE_IN_UNPROCESSED_HEADSET_MIC)},
@@ -898,6 +913,10 @@
         operator_specific_device_table[dev] = NULL;
     }
 
+    for (dev = 0; dev < SND_DEVICE_MAX; dev++) {
+        backend_bit_width_table[dev] = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+    }
+
     // To overwrite these go to the audio_platform_info.xml file.
     backend_tag_table[SND_DEVICE_IN_BT_SCO_MIC] = strdup("bt-sco");
     backend_tag_table[SND_DEVICE_IN_BT_SCO_MIC_NREC] = strdup("bt-sco");
@@ -910,6 +929,11 @@
     backend_tag_table[SND_DEVICE_OUT_VOICE_TX] = strdup("afe-proxy");
     backend_tag_table[SND_DEVICE_IN_VOICE_RX] = strdup("afe-proxy");
 
+    backend_tag_table[SND_DEVICE_OUT_USB_HEADSET] = strdup("usb-headset");
+    backend_tag_table[SND_DEVICE_OUT_USB_HEADPHONES] = strdup("usb-headphones");
+    backend_tag_table[SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] =
+        strdup("speaker-and-usb-headphones");
+    backend_tag_table[SND_DEVICE_IN_USB_HEADSET_MIC] = strdup("usb-headset-mic");
     hw_interface_table[SND_DEVICE_OUT_HANDSET] = strdup("SLIMBUS_0_RX");
     hw_interface_table[SND_DEVICE_OUT_SPEAKER] = strdup("SLIMBUS_0_RX");
     hw_interface_table[SND_DEVICE_OUT_SPEAKER_REVERSE] = strdup("SLIMBUS_0_RX");
@@ -933,6 +957,9 @@
     hw_interface_table[SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = strdup("SLIMBUS_0_RX");
     hw_interface_table[SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = strdup("SLIMBUS_0_RX");
     hw_interface_table[SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = strdup("SLIMBUS_0_RX");
+    hw_interface_table[SND_DEVICE_OUT_USB_HEADSET] = strdup("USB_AUDIO_RX");
+    hw_interface_table[SND_DEVICE_OUT_USB_HEADPHONES] = strdup("USB_AUDIO_RX");
+    hw_interface_table[SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = strdup("SLIMBUS_0_RX-and-USB_AUDIO_RX");
     hw_interface_table[SND_DEVICE_OUT_VOICE_TX] = strdup("AFE_PCM_RX");
     hw_interface_table[SND_DEVICE_OUT_SPEAKER_PROTECTED] = strdup("SLIMBUS_0_RX");
     hw_interface_table[SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = strdup("SLIMBUS_0_RX");
@@ -1000,6 +1027,57 @@
     return 0;
 }
 
+static void
+platform_backend_config_init(struct platform_data *pdata)
+{
+    int i;
+
+    /* initialize backend config */
+    for (i = 0; i < MAX_CODEC_BACKENDS; i++) {
+        pdata->current_backend_cfg[i].sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+        pdata->current_backend_cfg[i].bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+        pdata->current_backend_cfg[i].channels = CODEC_BACKEND_DEFAULT_CHANNELS;
+
+        if (i > MAX_RX_CODEC_BACKENDS)
+            pdata->current_backend_cfg[i].channels = CODEC_BACKEND_DEFAULT_TX_CHANNELS;
+
+        pdata->current_backend_cfg[i].bitwidth_mixer_ctl = NULL;
+        pdata->current_backend_cfg[i].samplerate_mixer_ctl = NULL;
+        pdata->current_backend_cfg[i].channels_mixer_ctl = NULL;
+    }
+
+    pdata->current_backend_cfg[DEFAULT_CODEC_BACKEND].bitwidth_mixer_ctl =
+            strdup("SLIM_0_RX Format");
+    pdata->current_backend_cfg[DEFAULT_CODEC_BACKEND].samplerate_mixer_ctl =
+            strdup("SLIM_0_RX SampleRate");
+
+    pdata->current_backend_cfg[DEFAULT_CODEC_TX_BACKEND].bitwidth_mixer_ctl =
+            strdup("SLIM_0_TX Format");
+    pdata->current_backend_cfg[DEFAULT_CODEC_TX_BACKEND].samplerate_mixer_ctl =
+            strdup("SLIM_0_TX SampleRate");
+
+    pdata->current_backend_cfg[USB_AUDIO_TX_BACKEND].bitwidth_mixer_ctl =
+            strdup("USB_AUDIO_TX Format");
+    pdata->current_backend_cfg[USB_AUDIO_TX_BACKEND].samplerate_mixer_ctl =
+            strdup("USB_AUDIO_TX SampleRate");
+    pdata->current_backend_cfg[USB_AUDIO_TX_BACKEND].channels_mixer_ctl =
+            strdup("USB_AUDIO_TX Channels");
+
+    pdata->current_backend_cfg[HEADPHONE_BACKEND].bitwidth_mixer_ctl =
+            strdup("SLIM_6_RX Format");
+    pdata->current_backend_cfg[HEADPHONE_BACKEND].samplerate_mixer_ctl =
+            strdup("SLIM_6_RX SampleRate");
+
+    pdata->current_backend_cfg[USB_AUDIO_RX_BACKEND].bitwidth_mixer_ctl =
+            strdup("USB_AUDIO_RX Format");
+    pdata->current_backend_cfg[USB_AUDIO_RX_BACKEND].samplerate_mixer_ctl =
+            strdup("USB_AUDIO_RX SampleRate");
+
+    pdata->current_backend_cfg[USB_AUDIO_RX_BACKEND].channels = 1;
+    pdata->current_backend_cfg[USB_AUDIO_RX_BACKEND].channels_mixer_ctl =
+            strdup("USB_AUDIO_RX Channels");
+}
+
 void *platform_init(struct audio_device *adev)
 {
     char value[PROPERTY_VALUE_MAX];
@@ -1298,6 +1376,9 @@
         platform_acdb_init(my_data);
     }
 
+    /* init usb */
+    audio_extn_usb_init(adev);
+
     audio_extn_spkr_prot_init(adev);
 
     audio_extn_hwdep_cal_send(adev->snd_card, my_data->acdb_handle);
@@ -1305,6 +1386,8 @@
     /* load csd client */
     platform_csd_init(my_data);
 
+    platform_backend_config_init(my_data);
+
     return my_data;
 
 init_failed:
@@ -1356,6 +1439,9 @@
     }
 
     free(platform);
+
+    /* deinit usb */
+    audio_extn_usb_deinit();
 }
 
 const char *platform_get_snd_device_name(snd_device_t snd_device)
@@ -1556,6 +1642,38 @@
         return acdb_device_table[snd_device];
 }
 
+static int platform_get_backend_index(snd_device_t snd_device)
+{
+    int32_t port = DEFAULT_CODEC_BACKEND;
+
+    if (snd_device >= SND_DEVICE_OUT_BEGIN && snd_device < SND_DEVICE_OUT_END) {
+        if (backend_tag_table[snd_device] != NULL) {
+                if (strncmp(backend_tag_table[snd_device], "headphones",
+                            sizeof("headphones")) == 0)
+                        port = HEADPHONE_BACKEND;
+                else if (strcmp(backend_tag_table[snd_device], "hdmi") == 0)
+                        port = HDMI_RX_BACKEND;
+                else if ((strcmp(backend_tag_table[snd_device], "usb-headphones") == 0) ||
+                           (strcmp(backend_tag_table[snd_device], "usb-headset") == 0))
+                        port = USB_AUDIO_RX_BACKEND;
+        }
+    } else if (snd_device >= SND_DEVICE_IN_BEGIN && snd_device < SND_DEVICE_IN_END) {
+        port = DEFAULT_CODEC_TX_BACKEND;
+        if (backend_tag_table[snd_device] != NULL) {
+                if (strcmp(backend_tag_table[snd_device], "usb-headset-mic") == 0)
+                        port = USB_AUDIO_TX_BACKEND;
+                else if (strstr(backend_tag_table[snd_device], "bt-sco") != NULL)
+                        port = BT_SCO_TX_BACKEND;
+        }
+    } else {
+        ALOGW("%s:napb: Invalid device - %d ", __func__, snd_device);
+    }
+
+    ALOGV("%s:napb: backend port - %d device - %d ", __func__, port, snd_device);
+
+    return port;
+}
+
 int platform_send_audio_calibration(void *platform, snd_device_t snd_device)
 {
     struct platform_data *my_data = (struct platform_data *)platform;
@@ -1919,6 +2037,12 @@
         new_snd_devices[0] = SND_DEVICE_OUT_SPEAKER_SAFE;
         new_snd_devices[1] = SND_DEVICE_OUT_LINE;
         ret = 0;
+    } else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET &&
+               !platform_check_backends_match(SND_DEVICE_OUT_SPEAKER, SND_DEVICE_OUT_USB_HEADSET)) {
+        *num_devices = 2;
+        new_snd_devices[0] = SND_DEVICE_OUT_SPEAKER;
+        new_snd_devices[1] = SND_DEVICE_OUT_USB_HEADSET;
+        ret = 0;
     }
     return ret;
 }
@@ -1957,6 +2081,9 @@
         } else if (devices == (AUDIO_DEVICE_OUT_AUX_DIGITAL |
                                AUDIO_DEVICE_OUT_SPEAKER)) {
             snd_device = SND_DEVICE_OUT_SPEAKER_AND_HDMI;
+        } else if (devices == (AUDIO_DEVICE_OUT_USB_DEVICE |
+                               AUDIO_DEVICE_OUT_SPEAKER)) {
+            snd_device = SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET;
         } else {
             ALOGE("%s: Invalid combo device(%#x)", __func__, devices);
             goto exit;
@@ -2037,7 +2164,12 @@
         }
     } else if (devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
         snd_device = SND_DEVICE_OUT_HDMI ;
-    } else if (devices & AUDIO_DEVICE_OUT_EARPIECE) {
+    } else if (devices & AUDIO_DEVICE_OUT_USB_DEVICE) {
+        if (audio_extn_usb_is_capture_supported())
+            snd_device = SND_DEVICE_OUT_USB_HEADSET;
+        else
+            snd_device = SND_DEVICE_OUT_USB_HEADPHONES;
+    }else if (devices & AUDIO_DEVICE_OUT_EARPIECE) {
         /*HAC support for voice-ish audio (eg visual voicemail)*/
         if(adev->voice.hac)
             snd_device = SND_DEVICE_OUT_VOICE_HAC_HANDSET;
@@ -2336,6 +2468,8 @@
             }
         } else if (in_device & AUDIO_DEVICE_IN_AUX_DIGITAL) {
             snd_device = SND_DEVICE_IN_HDMI_MIC;
+        } else if (in_device & AUDIO_DEVICE_IN_USB_DEVICE ) {
+            snd_device = SND_DEVICE_IN_USB_HEADSET_MIC;
         } else {
             ALOGE("%s: Unknown input device(s) %#x", __func__, in_device);
             ALOGW("%s: Using default handset-mic", __func__);
@@ -2376,6 +2510,11 @@
             }
         } else if (out_device & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
             snd_device = SND_DEVICE_IN_HDMI_MIC;
+        } else if (out_device & AUDIO_DEVICE_OUT_USB_DEVICE) {
+            if (audio_extn_usb_is_capture_supported())
+              snd_device = SND_DEVICE_IN_USB_HEADSET_MIC;
+            else
+              snd_device = SND_DEVICE_IN_SPEAKER_MIC;
         } else {
             ALOGE("%s: Unknown output device(s) %#x", __func__, out_device);
             ALOGW("%s: Using default handset-mic", __func__);
@@ -2636,27 +2775,6 @@
     }
 }
 
-bool platform_check_and_set_capture_backend_cfg(struct audio_device* adev,
-         struct audio_usecase *usecase __unused,
-         snd_device_t snd_device __unused)
-{
-    enum pcm_format  in_pcm_format = PCM_FORMAT_S16_LE;
-
-    if (adev && adev->active_input)
-        in_pcm_format = adev->active_input->config.format;
-
-    // allow 24 bit recording only if voice call is not active
-    if (!voice_is_in_call(adev) &&
-        adev->mode != AUDIO_MODE_IN_COMMUNICATION &&
-        in_pcm_format == PCM_FORMAT_S24_LE) {
-        audio_route_apply_and_update_path(adev->audio_route, "set-capture-format-24le");
-    } else {
-        audio_route_apply_and_update_path(adev->audio_route, "set-capture-format-default");
-    }
-
-    return true;
-}
-
 int platform_set_snd_device_backend(snd_device_t device, const char *backend_tag,
                                     const char * hw_interface)
 {
@@ -2879,3 +2997,464 @@
     }
     return 0;
 }
+
+/*
+ * configures afe with bit width and Sample Rate
+ */
+static int platform_set_backend_cfg(const struct audio_device* adev,
+                                          snd_device_t snd_device,
+                                          const struct audio_backend_cfg *backend_cfg)
+{
+
+    int ret = 0;
+    const int backend_idx = platform_get_backend_index(snd_device);
+    struct platform_data *my_data = (struct platform_data *)adev->platform;
+    const unsigned int bit_width = backend_cfg->bit_width;
+    const unsigned int sample_rate = backend_cfg->sample_rate;
+    const unsigned int channels = backend_cfg->channels;
+    const audio_format_t format = backend_cfg->format;
+    const bool passthrough_enabled = backend_cfg->passthrough_enabled;
+
+
+    ALOGV("%s:becf: afe: bitwidth %d, samplerate %d channels %d"
+          ", backend_idx %d device (%s)", __func__,  bit_width,
+          sample_rate, channels, backend_idx,
+          platform_get_snd_device_name(snd_device));
+
+    if ((my_data->current_backend_cfg[backend_idx].bitwidth_mixer_ctl) &&
+        (bit_width != my_data->current_backend_cfg[backend_idx].bit_width)) {
+
+        struct  mixer_ctl *ctl = NULL;
+        ctl = mixer_get_ctl_by_name(adev->mixer,
+                                    my_data->current_backend_cfg[backend_idx].bitwidth_mixer_ctl);
+        if (!ctl) {
+            ALOGE("%s:becf: afe: Could not get ctl for mixer command - %s",
+                  __func__,
+                  my_data->current_backend_cfg[backend_idx].bitwidth_mixer_ctl);
+            return -EINVAL;
+        }
+
+        if (bit_width == 24) {
+            if (format == AUDIO_FORMAT_PCM_24_BIT_PACKED)
+                ret = mixer_ctl_set_enum_by_string(ctl, "S24_3LE");
+            else
+                ret = mixer_ctl_set_enum_by_string(ctl, "S24_LE");
+        } else if (bit_width == 32) {
+            ret = mixer_ctl_set_enum_by_string(ctl, "S32_LE");
+        } else {
+            ret = mixer_ctl_set_enum_by_string(ctl, "S16_LE");
+        }
+        if ( ret < 0) {
+            ALOGE("%s:becf: afe: fail for %s mixer set to %d bit for %x format", __func__,
+                  my_data->current_backend_cfg[backend_idx].bitwidth_mixer_ctl, bit_width, format);
+        } else {
+            my_data->current_backend_cfg[backend_idx].bit_width = bit_width;
+            ALOGD("%s:becf: afe: %s mixer set to %d bit for %x format", __func__,
+                  my_data->current_backend_cfg[backend_idx].bitwidth_mixer_ctl, bit_width, format);
+        }
+        /* set the ret as 0 and not pass back to upper layer */
+        ret = 0;
+    }
+
+    if (passthrough_enabled || ((my_data->current_backend_cfg[backend_idx].samplerate_mixer_ctl) &&
+                                (sample_rate != my_data->current_backend_cfg[backend_idx].sample_rate))) {
+        char *rate_str = NULL;
+        struct  mixer_ctl *ctl = NULL;
+
+        switch (sample_rate) {
+            case 32000:
+                if (passthrough_enabled) {
+                    rate_str = "KHZ_32";
+                    break;
+                }
+            case 8000:
+            case 11025:
+            case 16000:
+            case 22050:
+            case 48000:
+                rate_str = "KHZ_48";
+                break;
+            case 44100:
+                rate_str = "KHZ_44P1";
+                break;
+            case 64000:
+            case 96000:
+                rate_str = "KHZ_96";
+                break;
+            case 88200:
+                rate_str = "KHZ_88P2";
+                break;
+            case 176400:
+                rate_str = "KHZ_176P4";
+                break;
+            case 192000:
+                rate_str = "KHZ_192";
+                break;
+            case 352800:
+                rate_str = "KHZ_352P8";
+                break;
+            case 384000:
+                rate_str = "KHZ_384";
+                break;
+            case 144000:
+                if (passthrough_enabled) {
+                    rate_str = "KHZ_144";
+                    break;
+                }
+            default:
+                rate_str = "KHZ_48";
+                break;
+        }
+
+        ctl = mixer_get_ctl_by_name(adev->mixer,
+                                    my_data->current_backend_cfg[backend_idx].samplerate_mixer_ctl);
+        if(!ctl) {
+            ALOGE("%s:becf: afe: Could not get ctl for mixer command - %s",
+                  __func__,
+                  my_data->current_backend_cfg[backend_idx].samplerate_mixer_ctl);
+            return -EINVAL;
+        }
+
+        ALOGD("%s:becf: afe: %s set to %s", __func__,
+              my_data->current_backend_cfg[backend_idx].samplerate_mixer_ctl, rate_str);
+        mixer_ctl_set_enum_by_string(ctl, rate_str);
+        my_data->current_backend_cfg[backend_idx].sample_rate = sample_rate;
+    }
+    if ((my_data->current_backend_cfg[backend_idx].channels_mixer_ctl) &&
+        (channels != my_data->current_backend_cfg[backend_idx].channels)) {
+        struct  mixer_ctl *ctl = NULL;
+        char *channel_cnt_str = NULL;
+
+        switch (channels) {
+            case 8:
+                channel_cnt_str = "Eight"; break;
+            case 7:
+                channel_cnt_str = "Seven"; break;
+            case 6:
+                channel_cnt_str = "Six"; break;
+            case 5:
+                channel_cnt_str = "Five"; break;
+            case 4:
+                channel_cnt_str = "Four"; break;
+            case 3:
+                channel_cnt_str = "Three"; break;
+            case 1:
+                channel_cnt_str = "One"; break;
+            case 2:
+            default:
+                channel_cnt_str = "Two"; break;
+        }
+
+        ctl = mixer_get_ctl_by_name(adev->mixer,
+                                    my_data->current_backend_cfg[backend_idx].channels_mixer_ctl);
+        if (!ctl) {
+            ALOGE("%s:becf: afe: Could not get ctl for mixer command - %s",
+                  __func__,
+                  my_data->current_backend_cfg[backend_idx].channels_mixer_ctl);
+            return -EINVAL;
+        }
+        mixer_ctl_set_enum_by_string(ctl, channel_cnt_str);
+        my_data->current_backend_cfg[backend_idx].channels = channels;
+
+        // skip EDID configuration for HDMI backend
+
+        ALOGD("%s:becf: afe: %s set to %s", __func__,
+              my_data->current_backend_cfg[backend_idx].channels_mixer_ctl,
+              channel_cnt_str);
+    }
+
+    // skip set ext_display format mixer control
+    return ret;
+}
+
+static int platform_get_snd_device_bit_width(snd_device_t snd_device)
+{
+    if ((snd_device < SND_DEVICE_MIN) || (snd_device >= SND_DEVICE_MAX)) {
+        ALOGE("%s: Invalid snd_device = %d", __func__, snd_device);
+        return CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+    }
+
+    return backend_bit_width_table[snd_device];
+}
+
+/*
+ * return backend_idx on which voice call is active
+ */
+static int platform_get_voice_call_backend(struct audio_device* adev)
+{
+    struct audio_usecase *uc = NULL;
+    struct listnode *node;
+    snd_device_t out_snd_device = SND_DEVICE_NONE;
+
+    int backend_idx = -1;
+
+    if (voice_is_in_call(adev) || adev->mode == AUDIO_MODE_IN_COMMUNICATION) {
+        list_for_each(node, &adev->usecase_list) {
+            uc =  node_to_item(node, struct audio_usecase, list);
+            if (uc && uc->type == VOICE_CALL && uc->stream.out) {
+                out_snd_device = platform_get_output_snd_device(adev->platform,
+                                                        uc->stream.out->devices);
+                backend_idx = platform_get_backend_index(out_snd_device);
+                break;
+            }
+        }
+    }
+    return backend_idx;
+}
+
+/*
+ * goes through all the current usecases and picks the highest
+ * bitwidth & samplerate
+ */
+static bool platform_check_capture_backend_cfg(struct audio_device* adev,
+                                   int backend_idx,
+                                   struct audio_backend_cfg *backend_cfg)
+{
+    bool backend_change = false;
+    unsigned int bit_width;
+    unsigned int sample_rate;
+    unsigned int channels;
+    struct platform_data *my_data = (struct platform_data *)adev->platform;
+
+    bit_width = backend_cfg->bit_width;
+    sample_rate = backend_cfg->sample_rate;
+    channels = backend_cfg->channels;
+
+    ALOGV("%s:txbecf: afe: Codec selected backend: %d current bit width: %d and "
+          "sample rate: %d, channels %d",__func__,backend_idx, bit_width,
+          sample_rate, channels);
+
+    // For voice calls use default configuration i.e. 16b/48K, only applicable to
+    // default backend
+    // force routing is not required here, caller will do it anyway
+    if (voice_is_in_call(adev) || adev->mode == AUDIO_MODE_IN_COMMUNICATION) {
+        ALOGW("%s:txbecf: afe: Use default bw and sr for voice/voip calls and "
+              "for unprocessed/camera source", __func__);
+        bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+        sample_rate =  CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+    }
+
+    if (backend_idx == USB_AUDIO_TX_BACKEND) {
+        audio_extn_usb_is_config_supported(&bit_width, &sample_rate, &channels, false);
+        ALOGV("%s:txbecf: afe: USB BE configured as bit_width(%d)sample_rate(%d)channels(%d)",
+              __func__, bit_width, sample_rate, channels);
+    }
+
+    ALOGV("%s:txbecf: afe: Codec selected backend: %d updated bit width: %d and "
+          "sample rate: %d", __func__, backend_idx, bit_width, sample_rate);
+
+    // Force routing if the expected bitwdith or samplerate
+    // is not same as current backend comfiguration
+    if ((bit_width != my_data->current_backend_cfg[backend_idx].bit_width) ||
+        (sample_rate != my_data->current_backend_cfg[backend_idx].sample_rate) ||
+        (channels != my_data->current_backend_cfg[backend_idx].channels)) {
+        backend_cfg->bit_width = bit_width;
+        backend_cfg->sample_rate= sample_rate;
+        backend_cfg->channels = channels;
+        backend_change = true;
+        ALOGI("%s:txbecf: afe: Codec backend needs to be updated. new bit width: %d "
+              "new sample rate: %d new channel: %d",
+              __func__, backend_cfg->bit_width,
+              backend_cfg->sample_rate, backend_cfg->channels);
+    }
+
+    return backend_change;
+}
+
+static bool platform_check_playback_backend_cfg(struct audio_device* adev,
+                                             struct audio_usecase* usecase,
+                                             snd_device_t snd_device,
+                                             struct audio_backend_cfg *backend_cfg)
+{
+    bool backend_change = false;
+    struct listnode *node;
+    unsigned int bit_width;
+    unsigned int sample_rate;
+    unsigned int channels;
+    bool passthrough_enabled = false;
+    int backend_idx = DEFAULT_CODEC_BACKEND;
+    struct platform_data *my_data = (struct platform_data *)adev->platform;
+    bool channels_updated = false;
+
+    if (snd_device == SND_DEVICE_OUT_BT_SCO ||
+        snd_device == SND_DEVICE_OUT_BT_SCO_WB) {
+        backend_change = false;
+        return backend_change;
+    }
+
+    backend_idx = platform_get_backend_index(snd_device);
+    bit_width = backend_cfg->bit_width;
+    sample_rate = backend_cfg->sample_rate;
+    channels = backend_cfg->channels;
+
+    ALOGV("%s:becf: afe: bitwidth %d, samplerate %d channels %d"
+          ", backend_idx %d usecase = %d device (%s)", __func__, bit_width,
+          sample_rate, channels, backend_idx, usecase->id,
+          platform_get_snd_device_name(snd_device));
+
+    if (backend_idx == platform_get_voice_call_backend(adev)) {
+        ALOGW("%s:becf: afe:Use default bw and sr for voice/voip calls ",
+              __func__);
+        bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+        sample_rate =  CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+        channels = CODEC_BACKEND_DEFAULT_CHANNELS;
+    } else {
+        /*
+         * The backend should be configured at highest bit width and/or
+         * sample rate amongst all playback usecases.
+         * If the selected sample rate and/or bit width differ with
+         * current backend sample rate and/or bit width, then, we set the
+         * backend re-configuration flag.
+         *
+         * Exception: 16 bit playbacks is allowed through 16 bit/48/44.1 khz backend only
+         */
+
+        int i =0;
+        list_for_each(node, &adev->usecase_list) {
+            struct audio_usecase *uc;
+            uc = node_to_item(node, struct audio_usecase, list);
+            struct stream_out *out = (struct stream_out*) uc->stream.out;
+            if (uc->type == PCM_PLAYBACK && out && usecase != uc) {
+                unsigned int out_channels = audio_channel_count_from_out_mask(out->channel_mask);
+
+                ALOGD("%s:napb: (%d) - (%s)id (%d) sr %d bw "
+                      "(%d) ch (%d) device %s", __func__, i++, use_case_table[uc->id],
+                      uc->id, out->sample_rate,
+                      pcm_format_to_bits(out->config.format), out_channels,
+                      platform_get_snd_device_name(uc->out_snd_device));
+
+                if (platform_check_backends_match(snd_device, uc->out_snd_device)) {
+                    if (bit_width < pcm_format_to_bits(out->config.format))
+                        bit_width = pcm_format_to_bits(out->config.format);
+                    if (sample_rate < out->sample_rate)
+                        sample_rate = out->sample_rate;
+                    if (out->sample_rate < OUTPUT_SAMPLING_RATE_44100)
+                        sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+                    if (channels < out_channels)
+                        channels = out_channels;
+                }
+            }
+        }
+    }
+
+    /*
+     * Check if the device is speaker or handset,assumption handset shares
+     * backend with speaker, and these devices are restricited to 48kHz.
+     */
+    if (platform_check_backends_match(SND_DEVICE_OUT_SPEAKER, snd_device)) {
+
+        if (bit_width >= 24) {
+            bit_width = platform_get_snd_device_bit_width(SND_DEVICE_OUT_SPEAKER);
+            ALOGD("%s:becf: afe: reset bitwidth to %d (based on supported"
+                  " value for this platform)", __func__, bit_width);
+        }
+        sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+        ALOGD("%s:becf: afe: playback on codec device not supporting native playback set "
+              "default Sample Rate(48k)", __func__);
+    }
+
+    if (backend_idx == USB_AUDIO_RX_BACKEND) {
+        audio_extn_usb_is_config_supported(&bit_width, &sample_rate, &channels, true);
+        ALOGV("%s: USB BE configured as bit_width(%d)sample_rate(%d)channels(%d)",
+              __func__, bit_width, sample_rate, channels);
+        if (channels != my_data->current_backend_cfg[backend_idx].channels)
+            channels_updated = true;
+    }
+
+    ALOGV("%s:becf: afe: Codec selected backend: %d updated bit width: %d and sample rate: %d",
+          __func__, backend_idx , bit_width, sample_rate);
+
+    // Force routing if the expected bitwdith or samplerate
+    // is not same as current backend comfiguration
+    if ((bit_width != my_data->current_backend_cfg[backend_idx].bit_width) ||
+        (sample_rate != my_data->current_backend_cfg[backend_idx].sample_rate) ||
+        passthrough_enabled || channels_updated) {
+        backend_cfg->bit_width = bit_width;
+        backend_cfg->sample_rate = sample_rate;
+        backend_cfg->channels = channels;
+        backend_cfg->passthrough_enabled = passthrough_enabled;
+        backend_change = true;
+        ALOGV("%s:becf: afe: Codec backend needs to be updated. new bit width: %d"
+              "new sample rate: %d new channels: %d",
+              __func__, backend_cfg->bit_width, backend_cfg->sample_rate, backend_cfg->channels);
+    }
+
+    return backend_change;
+}
+
+bool platform_check_and_set_playback_backend_cfg(struct audio_device* adev,
+    struct audio_usecase *usecase, snd_device_t snd_device)
+{
+    int backend_idx = DEFAULT_CODEC_BACKEND;
+    int new_snd_devices[SND_DEVICE_OUT_END];
+    int i, num_devices = 1;
+    bool ret = false;
+    struct platform_data *my_data = (struct platform_data *)adev->platform;
+    struct audio_backend_cfg backend_cfg;
+
+    backend_idx = platform_get_backend_index(snd_device);
+
+    backend_cfg.bit_width = pcm_format_to_bits(usecase->stream.out->config.format);
+    backend_cfg.sample_rate = usecase->stream.out->sample_rate;
+    backend_cfg.format = usecase->stream.out->format;
+    backend_cfg.channels = audio_channel_count_from_out_mask(usecase->stream.out->channel_mask);
+    /*this is populated by check_codec_backend_cfg hence set default value to false*/
+    backend_cfg.passthrough_enabled = false;
+
+    ALOGV("%s:becf: afe: bitwidth %d, samplerate %d channels %d"
+          ", backend_idx %d usecase = %d device (%s)", __func__, backend_cfg.bit_width,
+          backend_cfg.sample_rate, backend_cfg.channels, backend_idx, usecase->id,
+          platform_get_snd_device_name(snd_device));
+
+    if (platform_can_split_snd_device(snd_device, &num_devices, new_snd_devices) < 0)
+        new_snd_devices[0] = snd_device;
+
+    for (i = 0; i < num_devices; i++) {
+        ALOGV("%s: new_snd_devices[%d] is %d", __func__, i, new_snd_devices[i]);
+        if ((platform_check_playback_backend_cfg(adev, usecase, new_snd_devices[i],
+                                                 &backend_cfg))) {
+            platform_set_backend_cfg(adev, new_snd_devices[i],
+                                     &backend_cfg);
+            ret = true;
+        }
+    }
+    return ret;
+}
+
+bool platform_check_and_set_capture_backend_cfg(struct audio_device* adev,
+    struct audio_usecase *usecase, snd_device_t snd_device)
+{
+    int backend_idx = platform_get_backend_index(snd_device);
+    int ret = 0;
+    struct audio_backend_cfg backend_cfg;
+
+    backend_cfg.passthrough_enabled = false;
+
+    if(usecase->type == PCM_CAPTURE) {
+        backend_cfg.format= usecase->stream.in->format;
+        backend_cfg.channels = audio_channel_count_from_in_mask(usecase->stream.in->channel_mask);
+    } else {
+        backend_cfg.bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
+        backend_cfg.sample_rate =  CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+        backend_cfg.format = AUDIO_FORMAT_PCM_16_BIT;
+        backend_cfg.channels = 1;
+    }
+
+    ALOGV("%s:txbecf: afe: bitwidth %d, samplerate %d, channel %d"
+          ", backend_idx %d usecase = %d device (%s)", __func__,
+          backend_cfg.bit_width,
+          backend_cfg.sample_rate,
+          backend_cfg.channels,
+          backend_idx, usecase->id,
+          platform_get_snd_device_name(snd_device));
+
+    if (platform_check_capture_backend_cfg(adev, backend_idx, &backend_cfg)) {
+        ret = platform_set_backend_cfg(adev, snd_device,
+                                       &backend_cfg);
+        if(!ret)
+            return true;
+    }
+
+    return false;
+}
+
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index e6aee08..cc75384 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -41,6 +41,15 @@
      AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE | \
      AUDIO_DEVICE_OUT_LINE)
 
+/*
+ * Below are the input devices for which back end is same, SLIMBUS_0_TX.
+ * All these devices are handled by the internal HW codec. We can
+ * enable any one of these devices at any time
+ */
+#define AUDIO_DEVICE_IN_ALL_CODEC_BACKEND \
+    (AUDIO_DEVICE_IN_BUILTIN_MIC | AUDIO_DEVICE_IN_BACK_MIC | \
+     AUDIO_DEVICE_IN_WIRED_HEADSET | AUDIO_DEVICE_IN_VOICE_CALL) & ~AUDIO_DEVICE_BIT_IN
+
 /* Sound devices specific to the platform
  * The DEVICE_OUT_* and DEVICE_IN_* should be mapped to these sound
  * devices to enable corresponding mixer paths
@@ -78,6 +87,9 @@
     SND_DEVICE_OUT_SPEAKER_PROTECTED,
     SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED,
     SND_DEVICE_OUT_VOICE_SPEAKER_HFP,
+    SND_DEVICE_OUT_USB_HEADSET,
+    SND_DEVICE_OUT_USB_HEADPHONES,
+    SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET,
     SND_DEVICE_OUT_END,
 
     /*
@@ -142,6 +154,7 @@
 
     SND_DEVICE_IN_VOICE_RX,
 
+    SND_DEVICE_IN_USB_HEADSET_MIC,
     SND_DEVICE_IN_THREE_MIC,
     SND_DEVICE_IN_QUAD_MIC,
     SND_DEVICE_IN_CAPTURE_VI_FEEDBACK,
@@ -155,6 +168,24 @@
     SND_DEVICE_MAX = SND_DEVICE_IN_END,
 
 };
+#define DEFAULT_OUTPUT_SAMPLING_RATE    48000
+#define OUTPUT_SAMPLING_RATE_44100      44100
+enum {
+    DEFAULT_CODEC_BACKEND,
+    SLIMBUS_0_RX = DEFAULT_CODEC_BACKEND,
+    HEADPHONE_BACKEND,
+    SLIMBUS_6_RX = HEADPHONE_BACKEND,
+    HDMI_RX_BACKEND,
+    USB_AUDIO_RX_BACKEND,
+    MAX_RX_CODEC_BACKENDS = USB_AUDIO_RX_BACKEND,
+    /* TX BE follows RX BE */
+    SLIMBUS_0_TX,
+    DEFAULT_CODEC_TX_BACKEND = SLIMBUS_0_TX,
+    USB_AUDIO_TX_BACKEND,
+    BT_SCO_TX_BACKEND,
+    MAX_CODEC_BACKENDS
+};
+
 
 #define DEVICE_NAME_MAX_SIZE   128
 #define HW_INFO_ARRAY_MAX_SIZE 32
@@ -316,6 +347,23 @@
     get_sample_rate_t get_sample_rate;
 };
 
+struct audio_backend_cfg {
+    unsigned int   sample_rate;
+    unsigned int   channels;
+    unsigned int   bit_width;
+    bool           passthrough_enabled;
+    audio_format_t format;
+};
+
+typedef struct codec_backend_cfg {
+    uint32_t sample_rate;
+    uint32_t bit_width;
+    uint32_t channels;
+    char     *bitwidth_mixer_ctl;
+    char     *samplerate_mixer_ctl;
+    char     *channels_mixer_ctl;
+} codec_backend_cfg_t;
+
 #define PLATFORM_INFO_XML_PATH          "/system/etc/audio_platform_info.xml"
 #define PLATFORM_INFO_XML_BASE_STRING   "/system/etc/audio_platform_info"
 #endif // QCOM_AUDIO_PLATFORM_H
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 83554b0..59ad4b1 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -20,6 +20,12 @@
 #include "voice.h"
 #define MAX_VOLUME_CAL_STEPS 15
 #define CODEC_BACKEND_DEFAULT_SAMPLE_RATE 48000
+#define CODEC_BACKEND_DEFAULT_BIT_WIDTH 16
+#define CODEC_BACKEND_DEFAULT_CHANNELS 2
+#define CODEC_BACKEND_DEFAULT_TX_CHANNELS 1
+#define SAMPLE_RATE_8000 8000
+#define SAMPLE_RATE_11025 11025
+#define sample_rate_multiple(sr, base) ((sr % base)== 0?true:false)
 
 struct amp_db_and_gain_table {
     float amp;
@@ -112,6 +118,9 @@
 
 int platform_set_parameters(void *platform, struct str_parms *parms);
 
+bool platform_check_and_set_playback_backend_cfg(struct audio_device* adev,
+                   struct audio_usecase *usecase, snd_device_t snd_device);
+
 bool platform_check_and_set_capture_backend_cfg(struct audio_device* adev,
                    struct audio_usecase *usecase, snd_device_t snd_device);