Merge "Fix security vulnerability: Equalizer setParameter memory overflow" into lmp-dev am: 1f0f83e1ff am: b3ad2a046e am: dfd990face am: 9f623d6475 am: d4517e643b am: f4c3975abf am: 878d778986 am: a31de317d4 am: 025df90241 am: 853a6bc15f am: d9a108d531
am: 3f7ffd5d56

Change-Id: Icd744fb5e1f076a663887bf07c2507e2a1d355e3
diff --git a/hal/Android.mk b/hal/Android.mk
index f3d2798..2b27e64 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -74,7 +74,13 @@
   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 := \
+	libaudioutils \
 	liblog \
 	libcutils \
 	libtinyalsa \
@@ -122,6 +128,10 @@
     LOCAL_CFLAGS += -DSOUND_TRIGGER_PLATFORM_NAME=$(TARGET_BOARD_PLATFORM)
     LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/sound_trigger
     LOCAL_SRC_FILES += audio_extn/soundtrigger.c
+ifneq ($(filter msm8996,$(TARGET_BOARD_PLATFORM)),)
+LOCAL_HEADER_LIBRARIES := sound_trigger.primary_headers
+endif
+
 endif
 
 ifeq ($(strip $(AUDIO_FEATURE_ENABLED_SPKR_PROTECTION)),true)
@@ -152,6 +162,12 @@
 
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_MODULE_OWNER := qcom
+
+LOCAL_PROPRIETARY_MODULE := true
+
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_SHARED_LIBRARY)
 
 endif
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/ext_speaker.c b/hal/audio_extn/ext_speaker.c
index 080620d..1bf8e5b 100644
--- a/hal/audio_extn/ext_speaker.c
+++ b/hal/audio_extn/ext_speaker.c
@@ -23,9 +23,9 @@
 #include <dlfcn.h>
 
 #ifdef __LP64__
-#define LIB_SPEAKER_BUNDLE "/system/lib64/soundfx/libspeakerbundle.so"
+#define LIB_SPEAKER_BUNDLE "/vendor/lib64/soundfx/libspeakerbundle.so"
 #else
-#define LIB_SPEAKER_BUNDLE "/system/lib/soundfx/libspeakerbundle.so"
+#define LIB_SPEAKER_BUNDLE "/vendor/lib/soundfx/libspeakerbundle.so"
 #endif
 
 typedef void (*set_mode_t)(int);
diff --git a/hal/audio_extn/sndmonitor.c b/hal/audio_extn/sndmonitor.c
index d303c06..58ab43d 100644
--- a/hal/audio_extn/sndmonitor.c
+++ b/hal/audio_extn/sndmonitor.c
@@ -190,8 +190,10 @@
         }
 
         ret = add_new_sndcard(atoi(ptr), fd);
-        if (ret != 0)
+        if (ret != 0) {
+            close(fd); // card state fd ownership is taken by sndcard on success
             continue;
+        }
 
         num_cards++;
 
@@ -218,8 +220,10 @@
             continue;
 
         ret = add_new_sndcard(CPE_MAGIC_NUM+num_cpe, fd);
-        if (ret != 0)
+        if (ret != 0) {
+            close(fd); // card state fd ownership is taken by sndcard on success
             continue;
+        }
 
         num_cpe++;
         num_cards++;
@@ -578,8 +582,12 @@
 
     write(sndmonitor.intpipe[1], "Q", 1);
     pthread_join(sndmonitor.monitor_thread, (void **) NULL);
-    free_sndcards();
     free_dev_events();
+    listeners_deinit();
+    free_sndcards();
+    close(sndmonitor.intpipe[0]);
+    close(sndmonitor.intpipe[1]);
+
     sndmonitor.initcheck = 0;
     return 0;
 }
@@ -593,13 +601,13 @@
     sndmonitor.initcheck = false;
 
     if (pipe(sndmonitor.intpipe) < 0)
-        return -ENODEV;
+        goto pipe_error;
 
     if (enum_sndcards() < 0)
-        return -ENODEV;
+        goto enum_sncards_error;
 
     if (listeners_init() < 0)
-        return -ENODEV;
+        goto listeners_error;
 
 #ifdef MONITOR_DEVICE_EVENTS
     enum_dev_events(); // failure here isn't fatal
@@ -610,14 +618,20 @@
                              monitor_thread_loop, NULL);
 
     if (ret) {
-        free_sndcards();
-        free_dev_events();
-        close(sndmonitor.intpipe[0]);
-        close(sndmonitor.intpipe[1]);
-        return -ENODEV;
+        goto monitor_thread_create_error;
     }
     sndmonitor.initcheck = true;
     return 0;
+
+monitor_thread_create_error:
+    listeners_deinit();
+listeners_error:
+    free_sndcards();
+enum_sncards_error:
+    close(sndmonitor.intpipe[0]);
+    close(sndmonitor.intpipe[1]);
+pipe_error:
+    return -ENODEV;
 }
 
 int audio_extn_snd_mon_register_listener(void *stream, snd_mon_cb cb)
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 0a5bccb..6f0c9c9 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -33,6 +33,7 @@
 #include <dlfcn.h>
 #include <sys/resource.h>
 #include <sys/prctl.h>
+#include <limits.h>
 
 #include <cutils/log.h>
 #include <cutils/trace.h>
@@ -44,8 +45,11 @@
 #include <hardware/audio_effect.h>
 #include <hardware/audio_alsaops.h>
 #include <system/thread_defs.h>
+#include <tinyalsa/asoundlib.h>
 #include <audio_effects/effect_aec.h>
 #include <audio_effects/effect_ns.h>
+#include <audio_utils/clock.h>
+#include <audio_utils/power.h>
 #include "audio_hw.h"
 #include "audio_extn.h"
 #include "platform_api.h"
@@ -83,6 +87,13 @@
 static unsigned int configured_low_latency_capture_period_size =
         LOW_LATENCY_CAPTURE_PERIOD_SIZE;
 
+
+#define MMAP_PERIOD_SIZE (DEFAULT_OUTPUT_SAMPLING_RATE/1000)
+#define MMAP_PERIOD_COUNT_MIN 32
+#define MMAP_PERIOD_COUNT_MAX 512
+#define MMAP_PERIOD_COUNT_DEFAULT (MMAP_PERIOD_COUNT_MAX)
+
+
 /* This constant enables extended precision handling.
  * TODO The flag is off until more testing is done.
  */
@@ -135,6 +146,19 @@
     .avail_min = 0,
 };
 
+struct pcm_config pcm_config_mmap_playback = {
+    .channels = DEFAULT_CHANNEL_COUNT,
+    .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
+    .period_size = MMAP_PERIOD_SIZE,
+    .period_count = MMAP_PERIOD_COUNT_DEFAULT,
+    .format = PCM_FORMAT_S16_LE,
+    .start_threshold = MMAP_PERIOD_SIZE*8,
+    .stop_threshold = INT32_MAX,
+    .silence_threshold = 0,
+    .silence_size = 0,
+    .avail_min = MMAP_PERIOD_SIZE, //1 ms
+};
+
 struct pcm_config pcm_config_audio_capture = {
     .channels = DEFAULT_CHANNEL_COUNT,
     .period_count = AUDIO_CAPTURE_PERIOD_COUNT,
@@ -156,6 +180,19 @@
     .avail_min = ULL_PERIOD_SIZE, //1 ms
 };
 
+struct pcm_config pcm_config_mmap_capture = {
+    .channels = DEFAULT_CHANNEL_COUNT,
+    .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
+    .period_size = MMAP_PERIOD_SIZE,
+    .period_count = MMAP_PERIOD_COUNT_DEFAULT,
+    .format = PCM_FORMAT_S16_LE,
+    .start_threshold = 0,
+    .stop_threshold = INT_MAX,
+    .silence_threshold = 0,
+    .silence_size = 0,
+    .avail_min = MMAP_PERIOD_SIZE, //1 ms
+};
+
 #define AFE_PROXY_CHANNEL_COUNT 2
 #define AFE_PROXY_SAMPLING_RATE 48000
 
@@ -194,9 +231,11 @@
     [USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback",
     [USECASE_AUDIO_PLAYBACK_TTS] = "audio-tts-playback",
     [USECASE_AUDIO_PLAYBACK_ULL] = "audio-ull-playback",
+    [USECASE_AUDIO_PLAYBACK_MMAP] = "mmap-playback",
 
     [USECASE_AUDIO_RECORD] = "audio-record",
     [USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record",
+    [USECASE_AUDIO_RECORD_MMAP] = "mmap-record",
 
     [USECASE_AUDIO_HFP_SCO] = "hfp-sco",
     [USECASE_AUDIO_HFP_SCO_WB] = "hfp-sco-wb",
@@ -232,11 +271,19 @@
 
 static int set_voice_volume_l(struct audio_device *adev, float volume);
 static struct audio_device *adev = NULL;
-static pthread_mutex_t adev_init_lock;
+static pthread_mutex_t adev_init_lock = PTHREAD_MUTEX_INITIALIZER;
 static unsigned int audio_device_ref_count;
 //cache last MBDRC cal step level
 static int last_known_cal_step = -1 ;
 
+// TODO: Consider moving this to a pthread_once() if we have more
+// static initialization required.
+static bool is_userdebug_or_eng_build() {
+    char value[PROPERTY_VALUE_MAX];
+    (void)property_get("ro.build.type", value, "unknown"); // ignore actual length
+    return strcmp(value, "userdebug") == 0 || strcmp(value, "eng") == 0;
+}
+
 static bool may_use_noirq_mode(struct audio_device *adev, audio_usecase_t uc_id,
                                int flags __unused)
 {
@@ -306,12 +353,6 @@
 {
     struct audio_device *adev = out->dev;
 
-    if (out->routing_change) {
-        out->routing_change = false;
-        if (adev->adm_on_routing_change)
-            adev->adm_on_routing_change(adev->adm_data, out->handle);
-    }
-
     if (adev->adm_request_focus_v2) {
         adev->adm_request_focus_v2(adev->adm_data, out->handle, ns);
     } else if (adev->adm_request_focus) {
@@ -323,12 +364,6 @@
 {
     struct audio_device *adev = in->dev;
 
-    if (in->routing_change) {
-        in->routing_change = false;
-        if (adev->adm_on_routing_change)
-            adev->adm_on_routing_change(adev->adm_data, in->capture_handle);
-    }
-
     if (adev->adm_request_focus_v2) {
         adev->adm_request_focus_v2(adev->adm_data, in->capture_handle, ns);
     } else if (adev->adm_request_focus) {
@@ -351,79 +386,6 @@
         adev->adm_abandon_focus(adev->adm_data, in->capture_handle);
 }
 
-// Time string format similar to logcat, buffer_length must be >= 19 chars.
-static void ns2string(int64_t ns, char *buffer, int buffer_length)
-{
-    const int one_second = 1000000000;
-    const time_t sec = ns / one_second;
-    struct tm tm;
-    localtime_r(&sec, &tm);
-    snprintf(buffer, buffer_length, "%02d-%02d %02d:%02d:%02d.%03d",
-        tm.tm_mon + 1, // localtime_r uses months in 0 - 11 range
-        tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
-        (int)(ns % one_second / 1000000));
-}
-
-// Convert timespec to nsec.
-static int64_t ts2ns(const struct timespec *ts)
-{
-    return ts->tv_sec * 1000000000LL + ts->tv_nsec;
-}
-
-// Log errors: consecutive errors with the same code will
-// be aggregated if they occur within one second.
-// A mutual exclusion lock must be held before calling.
-static void log_error_l(struct error_log *log, int code) {
-    ++log->errors;
-
-    struct timespec now_ts = { 0, 0 };
-    (void)clock_gettime(CLOCK_REALTIME, &now_ts);
-    const int64_t now = ts2ns(&now_ts);
-
-    // Within 1 second, cluster the same error codes together.
-    const int one_second = 1000000000;
-    if (code == log->entries[log->idx].code &&
-            now - log->entries[log->idx].last_time < one_second) {
-        log->entries[log->idx].count++;
-        log->entries[log->idx].last_time = now;
-        return;
-    }
-
-    // Add new error entry.
-    if (++log->idx >= ARRAY_SIZE(log->entries)) {
-        log->idx = 0;
-    }
-    log->entries[log->idx].count = 1;
-    log->entries[log->idx].code = code;
-    log->entries[log->idx].first_time = now;
-    log->entries[log->idx].last_time = now;
-}
-
-// Dump information in the error log. A mutual exclusion lock
-// should be held, but if that cannot be obtained, one should
-// make a copy of the error log before calling -- the call is
-// still safe, but there might be some misinterpreted data.
-static void log_dump_l(const struct error_log *log, int fd)
-{
-    dprintf(fd, "      Errors: %u\n", log->errors);
-    if (log->errors == 0)
-        return;
-
-    dprintf(fd, "      Index Code  Freq          First time           Last time\n");
-    for (size_t i = 0; i < ARRAY_SIZE(log->entries); ++i) {
-        if (log->entries[i].count != 0) {
-            char first_time[32];
-            char last_time[32];
-            ns2string(log->entries[i].first_time, first_time, sizeof(first_time));
-            ns2string(log->entries[i].last_time, last_time, sizeof(last_time));
-            dprintf(fd, "      %c%4zu %4d %5d  %s  %s\n",
-                    i == log->idx ? '*' : ' ', // mark head position
-                    i, log->entries[i].code, log->entries[i].count,
-                    first_time, last_time);
-        }
-    }
-}
-
 static int parse_snd_card_status(struct str_parms * parms, int * card,
                                  card_status_t * status)
 {
@@ -822,6 +784,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
@@ -1166,7 +1130,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);
     }
@@ -1276,60 +1241,72 @@
 
     select_devices(adev, in->usecase);
 
-    ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
-          __func__, adev->snd_card, in->pcm_device_id, in->config.channels);
-
-    unsigned int flags = PCM_IN | PCM_MONOTONIC;
-    unsigned int pcm_open_retry_count = 0;
-
-    if (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY) {
-        flags |= PCM_MMAP | PCM_NOIRQ;
-        pcm_open_retry_count = PROXY_OPEN_RETRY_COUNT;
-    } else if (in->realtime) {
-        flags |= PCM_MMAP | PCM_NOIRQ;
-    }
-
-    while (1) {
-        in->pcm = pcm_open(adev->snd_card, in->pcm_device_id,
-                           flags, &in->config);
+    if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
         if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
-            ALOGE("%s: %s", __func__, pcm_get_error(in->pcm));
-            if (in->pcm != NULL) {
-                pcm_close(in->pcm);
-                in->pcm = NULL;
-            }
-            if (pcm_open_retry_count-- == 0) {
-                ret = -EIO;
-                goto error_open;
-            }
-            usleep(PROXY_OPEN_WAIT_TIME * 1000);
-            continue;
+            ALOGE("%s: pcm stream not ready", __func__);
+            goto error_open;
         }
-        break;
-    }
-
-    ALOGV("%s: pcm_prepare", __func__);
-    ret = pcm_prepare(in->pcm);
-    if (ret < 0) {
-        ALOGE("%s: pcm_prepare returned %d", __func__, ret);
-        pcm_close(in->pcm);
-        in->pcm = NULL;
-        goto error_open;
-    }
-    if (in->realtime) {
         ret = pcm_start(in->pcm);
         if (ret < 0) {
-            ALOGE("%s: RT pcm_start failed ret %d", __func__, ret);
+            ALOGE("%s: MMAP pcm_start failed ret %d", __func__, ret);
+            goto error_open;
+        }
+    } else {
+        unsigned int flags = PCM_IN | PCM_MONOTONIC;
+        unsigned int pcm_open_retry_count = 0;
+
+        if (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY) {
+            flags |= PCM_MMAP | PCM_NOIRQ;
+            pcm_open_retry_count = PROXY_OPEN_RETRY_COUNT;
+        } else if (in->realtime) {
+            flags |= PCM_MMAP | PCM_NOIRQ;
+        }
+
+        ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
+              __func__, adev->snd_card, in->pcm_device_id, in->config.channels);
+
+        while (1) {
+            in->pcm = pcm_open(adev->snd_card, in->pcm_device_id,
+                               flags, &in->config);
+            if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
+                ALOGE("%s: %s", __func__, pcm_get_error(in->pcm));
+                if (in->pcm != NULL) {
+                    pcm_close(in->pcm);
+                    in->pcm = NULL;
+                }
+                if (pcm_open_retry_count-- == 0) {
+                    ret = -EIO;
+                    goto error_open;
+                }
+                usleep(PROXY_OPEN_WAIT_TIME * 1000);
+                continue;
+            }
+            break;
+        }
+
+        ALOGV("%s: pcm_prepare", __func__);
+        ret = pcm_prepare(in->pcm);
+        if (ret < 0) {
+            ALOGE("%s: pcm_prepare returned %d", __func__, ret);
             pcm_close(in->pcm);
             in->pcm = NULL;
             goto error_open;
         }
+        if (in->realtime) {
+            ret = pcm_start(in->pcm);
+            if (ret < 0) {
+                ALOGE("%s: RT pcm_start failed ret %d", __func__, ret);
+                pcm_close(in->pcm);
+                in->pcm = NULL;
+                goto error_open;
+            }
+        }
     }
     register_in_stream(in);
     audio_extn_perf_lock_release();
     ALOGV("%s: exit", __func__);
 
-    return ret;
+    return 0;
 
 error_open:
     stop_input_stream(in);
@@ -1667,8 +1644,36 @@
 
     ALOGV("%s: Opening PCM device card_id(%d) device_id(%d) format(%#x)",
           __func__, adev->snd_card, out->pcm_device_id, out->config.format);
-    if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) {
-        unsigned int flags = PCM_OUT;
+    if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
+        out->pcm = NULL;
+        out->compr = compress_open(adev->snd_card, out->pcm_device_id,
+                                   COMPRESS_IN, &out->compr_config);
+        if (out->compr && !is_compress_ready(out->compr)) {
+            ALOGE("%s: %s", __func__, compress_get_error(out->compr));
+            compress_close(out->compr);
+            out->compr = NULL;
+            ret = -EIO;
+            goto error_open;
+        }
+        if (out->offload_callback)
+            compress_nonblock(out->compr, out->non_blocking);
+
+        if (adev->visualizer_start_output != NULL)
+            adev->visualizer_start_output(out->handle, out->pcm_device_id);
+        if (adev->offload_effects_start_output != NULL)
+            adev->offload_effects_start_output(out->handle, out->pcm_device_id);
+    } else if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
+        if (out->pcm == NULL || !pcm_is_ready(out->pcm)) {
+            ALOGE("%s: pcm stream not ready", __func__);
+            goto error_open;
+        }
+        ret = pcm_start(out->pcm);
+        if (ret < 0) {
+            ALOGE("%s: MMAP pcm_start failed ret %d", __func__, ret);
+            goto error_open;
+        }
+    } else {
+        unsigned int flags = PCM_OUT | PCM_MONOTONIC;
         unsigned int pcm_open_retry_count = 0;
 
         if (out->usecase == USECASE_AUDIO_PLAYBACK_AFE_PROXY) {
@@ -1676,8 +1681,7 @@
             pcm_open_retry_count = PROXY_OPEN_RETRY_COUNT;
         } else if (out->realtime) {
             flags |= PCM_MMAP | PCM_NOIRQ;
-        } else
-            flags |= PCM_MONOTONIC;
+        }
 
         while (1) {
             out->pcm = pcm_open(adev->snd_card, out->pcm_device_id,
@@ -1707,33 +1711,14 @@
                 goto error_open;
             }
         }
-    } else {
-        out->pcm = NULL;
-        out->compr = compress_open(adev->snd_card, out->pcm_device_id,
-                                   COMPRESS_IN, &out->compr_config);
-        if (out->compr && !is_compress_ready(out->compr)) {
-            ALOGE("%s: %s", __func__, compress_get_error(out->compr));
-            compress_close(out->compr);
-            out->compr = NULL;
-            ret = -EIO;
-            goto error_open;
-        }
-        if (out->offload_callback)
-            compress_nonblock(out->compr, out->non_blocking);
-
-        if (adev->visualizer_start_output != NULL)
-            adev->visualizer_start_output(out->handle, out->pcm_device_id);
-        if (adev->offload_effects_start_output != NULL)
-            adev->offload_effects_start_output(out->handle, out->pcm_device_id);
-    }
-    ret = 0;
-    if (out->realtime) {
-        ret = pcm_start(out->pcm);
-        if (ret < 0) {
-            ALOGE("%s: RT pcm_start failed ret %d", __func__, ret);
-            pcm_close(out->pcm);
-            out->pcm = NULL;
-            goto error_open;
+        if (out->realtime) {
+            ret = pcm_start(out->pcm);
+            if (ret < 0) {
+                ALOGE("%s: RT pcm_start failed ret %d", __func__, ret);
+                pcm_close(out->pcm);
+                out->pcm = NULL;
+                goto error_open;
+            }
         }
     }
     register_out_stream(out);
@@ -1741,7 +1726,7 @@
     audio_extn_tfa_98xx_enable_speaker();
 
     ALOGV("%s: exit", __func__);
-    return ret;
+    return 0;
 error_open:
     audio_extn_perf_lock_release();
     stop_output_stream(out);
@@ -1856,6 +1841,7 @@
 {
     struct stream_out *out = (struct stream_out *)stream;
     struct audio_device *adev = out->dev;
+    bool do_stop = true;
 
     ALOGV("%s: enter: usecase(%d: %s)", __func__,
           out->usecase, use_case_table[out->usecase]);
@@ -1864,7 +1850,6 @@
     if (!out->standby) {
         if (adev->adm_deregister_stream)
             adev->adm_deregister_stream(adev->adm_data, out->handle);
-
         pthread_mutex_lock(&adev->lock);
         out->standby = true;
         if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) {
@@ -1872,6 +1857,10 @@
                 pcm_close(out->pcm);
                 out->pcm = NULL;
             }
+            if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
+                do_stop = out->playback_started;
+                out->playback_started = false;
+            }
         } else {
             stop_compressed_output_l(out);
             out->gapless_mdata.encoder_delay = 0;
@@ -1881,7 +1870,9 @@
                 out->compr = NULL;
             }
         }
-        stop_output_stream(out);
+        if (do_stop) {
+            stop_output_stream(out);
+        }
         pthread_mutex_unlock(&adev->lock);
     }
     pthread_mutex_unlock(&out->lock);
@@ -1923,13 +1914,15 @@
     dprintf(fd, "      Frames written: %lld\n", (long long)out->written);
 
     if (locked) {
-        log_dump_l(&out->error_log, fd);
         pthread_mutex_unlock(&out->lock);
-    } else {
-        // We don't have the lock here, copy for safety.
-        struct error_log log = out->error_log;
-        log_dump_l(&log, fd);
     }
+
+    // dump error info
+    (void)error_log_dump(
+            out->error_log, fd, "      " /* prefix */, 0 /* lines */, 0 /* limit_ns */);
+    // dump power info (out->power_log may be null)
+    (void)power_log_dump(
+            out->power_log, fd, "      " /* prefix */, POWER_LOG_LINES, 0 /* limit_ns */);
     return 0;
 }
 
@@ -2041,7 +2034,11 @@
             if (!out->standby) {
                 if (!same_dev) {
                     ALOGV("update routing change");
-                    out->routing_change = true;
+                    // inform adm before actual routing to prevent glitches.
+                    if (adev->adm_on_routing_change) {
+                        adev->adm_on_routing_change(adev->adm_data,
+                                                    out->handle);
+                    }
                 }
                 select_devices(adev, out->usecase);
                 audio_extn_tfa_98xx_update();
@@ -2096,7 +2093,7 @@
         str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value);
         str = str_parms_to_str(reply);
     } else {
-        str = strdup(keys);
+        str = strdup("");
     }
     str_parms_destroy(query);
     str_parms_destroy(reply);
@@ -2111,7 +2108,8 @@
 
     if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD)
         return COMPRESS_OFFLOAD_PLAYBACK_LATENCY;
-    else if (out->realtime) {
+    else if ((out->realtime) ||
+            (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP)) {
         // since the buffer won't be filled up faster than realtime,
         // return a smaller number
         period_ms = (out->af_period_multiplier * out->config.period_size *
@@ -2200,39 +2198,18 @@
 
 #ifdef NO_AUDIO_OUT
 static ssize_t out_write_for_no_output(struct audio_stream_out *stream,
-                                       const void *buffer, size_t bytes)
+                                       const void *buffer __unused, size_t bytes)
 {
     struct stream_out *out = (struct stream_out *)stream;
-    struct timespec t = { .tv_sec = 0, .tv_nsec = 0 };
-    int64_t now;
-    int64_t elapsed_time_since_last_write = 0;
-    int64_t sleep_time;
 
-    clock_gettime(CLOCK_MONOTONIC, &t);
-    now = (t.tv_sec * 1000000000LL + t.tv_nsec) / 1000;
-
+    /* No Output device supported other than BT for playback.
+     * Sleep for the amount of buffer duration
+     */
     lock_output_stream(out);
-    if (out->last_write_time_us)
-        elapsed_time_since_last_write = now - out->last_write_time_us;
-    sleep_time = bytes * 1000000LL / audio_stream_out_frame_size(stream) /
-               out_get_sample_rate(&stream->common) - elapsed_time_since_last_write;
-    if (sleep_time > 0) {
-        usleep(sleep_time);
-    } else {
-        // we don't sleep when we exit standby (this is typical for a real alsa buffer).
-        sleep_time = 0;
-    }
-    out->last_write_time_us = now + sleep_time;
+    usleep(bytes * 1000000 / audio_stream_out_frame_size(
+            (const struct audio_stream_out *)&out->stream) /
+            out_get_sample_rate(&out->stream.common));
     pthread_mutex_unlock(&out->lock);
-    // last_write_time_us is an approximation of when the (simulated) alsa
-    // buffer is believed completely full. The usleep above waits for more space
-    // in the buffer, but by the end of the sleep the buffer is considered
-    // topped-off.
-    //
-    // On the subsequent out_write(), we measure the elapsed time spent in
-    // the mixer. This is subtracted from the sleep estimate based on frames,
-    // thereby accounting for drain in the alsa buffer during mixing.
-    // This is a crude approximation; we don't handle underruns precisely.
     return bytes;
 }
 #endif
@@ -2246,6 +2223,13 @@
     int error_code = ERROR_CODE_STANDBY;
 
     lock_output_stream(out);
+    // this is always nonzero
+    const int frame_size = audio_stream_out_frame_size(stream);
+
+    if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
+        error_code = ERROR_CODE_WRITE;
+        goto exit;
+    }
     if (out->standby) {
         out->standby = false;
         pthread_mutex_lock(&adev->lock);
@@ -2264,7 +2248,7 @@
     }
 
     if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
-        ALOGVV("%s: writing buffer (%d bytes) to compress device", __func__, bytes);
+        ALOGVV("%s: writing buffer (%zu bytes) to compress device", __func__, bytes);
         if (out->send_new_metadata) {
             ALOGVV("send new gapless metadata");
             compress_set_gapless_metadata(out->compr, &out->gapless_mdata);
@@ -2297,9 +2281,12 @@
             out->offload_state = OFFLOAD_STATE_PLAYING;
         }
         if (ret < 0) {
-            log_error_l(&out->error_log, ERROR_CODE_WRITE);
+            error_log_log(out->error_log, ERROR_CODE_WRITE, audio_utils_get_real_time_ns());
+        } else {
+            out->written += ret; // accumulate bytes written for offload.
         }
         pthread_mutex_unlock(&out->lock);
+        // TODO: consider logging offload pcm
         return ret;
     } else {
         error_code = ERROR_CODE_WRITE;
@@ -2307,7 +2294,7 @@
             if (out->muted)
                 memset((void *)buffer, 0, bytes);
 
-            ALOGVV("%s: writing buffer (%d bytes) to pcm device", __func__, bytes);
+            ALOGVV("%s: writing buffer (%zu bytes) to pcm device", __func__, bytes);
 
             long ns = pcm_bytes_to_frames(out->pcm, bytes)*1000000000LL/
                                                 out->config.rate;
@@ -2331,12 +2318,18 @@
         out->written += bytes / (out->config.channels * sizeof(short));
     }
     long long sleeptime_us = 0;
+
+    // only get time if needed for logging, as it is a system call on 32 bit devices.
+    // TODO: Consider always enabling for 64 bit vDSO using compile time check on __LP64__.
+    const int64_t now_ns = out->power_log != 0 || (ret != 0 && out->error_log != 0)
+            ? audio_utils_get_real_time_ns() : 0;
+
     if (ret != 0) {
-        log_error_l(&out->error_log, error_code);
+        error_log_log(out->error_log, error_code, now_ns);
         if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) {
             ALOGE_IF(out->pcm != NULL,
                     "%s: error %zd - %s", __func__, ret, pcm_get_error(out->pcm));
-            sleeptime_us = bytes * 1000000LL / audio_stream_out_frame_size(stream) /
+            sleeptime_us = bytes * 1000000LL / frame_size /
                 out_get_sample_rate(&out->stream.common);
             // usleep not guaranteed for values over 1 second but we don't limit here.
         }
@@ -2348,6 +2341,9 @@
         out_on_error(&out->stream.common);
         if (sleeptime_us != 0)
             usleep(sleeptime_us);
+    } else {
+        // only log if the data is properly written (out->power_log may be null)
+        power_log_log(out->power_log, buffer, bytes / frame_size, now_ns);
     }
     return bytes;
 }
@@ -2370,7 +2366,7 @@
         pthread_mutex_unlock(&out->lock);
         return 0;
     } else
-        return -EINVAL;
+        return -ENODATA;
 }
 
 static int out_add_audio_effect(const struct audio_stream *stream __unused,
@@ -2388,14 +2384,14 @@
 static int out_get_next_write_timestamp(const struct audio_stream_out *stream __unused,
                                         int64_t *timestamp __unused)
 {
-    return -EINVAL;
+    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;
-    int ret = -EINVAL;
+    int ret = -ENODATA;
     unsigned long dsp_frames;
 
     lock_output_stream(out);
@@ -2512,6 +2508,170 @@
     return -ENOSYS;
 }
 
+static int out_stop(const struct audio_stream_out* stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    struct audio_device *adev = out->dev;
+    int ret = -ENOSYS;
+
+    ALOGV("%s", __func__);
+    pthread_mutex_lock(&adev->lock);
+    if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP && !out->standby &&
+            out->playback_started && out->pcm != NULL) {
+        pcm_stop(out->pcm);
+        ret = stop_output_stream(out);
+        out->playback_started = false;
+    }
+    pthread_mutex_unlock(&adev->lock);
+    return ret;
+}
+
+static int out_start(const struct audio_stream_out* stream)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    struct audio_device *adev = out->dev;
+    int ret = -ENOSYS;
+
+    ALOGV("%s", __func__);
+    pthread_mutex_lock(&adev->lock);
+    if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP && !out->standby &&
+            !out->playback_started && out->pcm != NULL) {
+        ret = start_output_stream(out);
+        if (ret == 0) {
+            out->playback_started = true;
+        }
+    }
+    pthread_mutex_unlock(&adev->lock);
+    return ret;
+}
+
+/*
+ * Modify config->period_count based on min_size_frames
+ */
+static void adjust_mmap_period_count(struct pcm_config *config, int32_t min_size_frames)
+{
+    int periodCountRequested = (min_size_frames + config->period_size - 1)
+                               / config->period_size;
+    int periodCount = MMAP_PERIOD_COUNT_MIN;
+
+    ALOGV("%s original config.period_size = %d config.period_count = %d",
+          __func__, config->period_size, config->period_count);
+
+    while (periodCount < periodCountRequested && (periodCount * 2) < MMAP_PERIOD_COUNT_MAX) {
+        periodCount *= 2;
+    }
+    config->period_count = periodCount;
+
+    ALOGV("%s requested config.period_count = %d", __func__, config->period_count);
+}
+
+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->dev;
+    int ret = 0;
+    unsigned int offset1;
+    unsigned int frames1;
+    const char *step = "";
+
+    ALOGV("%s", __func__);
+    pthread_mutex_lock(&adev->lock);
+
+    if (info == NULL || min_size_frames == 0) {
+        ALOGE("%s: info = %p, min_size_frames = %d", __func__, info, min_size_frames);
+        ret = -EINVAL;
+        goto exit;
+    }
+    if (out->usecase != USECASE_AUDIO_PLAYBACK_MMAP || !out->standby) {
+        ALOGE("%s: usecase = %d, standby = %d", __func__, out->usecase, out->standby);
+        ret = -ENOSYS;
+        goto exit;
+    }
+    out->pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
+    if (out->pcm_device_id < 0) {
+        ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
+              __func__, out->pcm_device_id, out->usecase);
+        ret = -EINVAL;
+        goto exit;
+    }
+
+    adjust_mmap_period_count(&out->config, min_size_frames);
+
+    ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
+          __func__, adev->snd_card, out->pcm_device_id, out->config.channels);
+    out->pcm = pcm_open(adev->snd_card, out->pcm_device_id,
+                        (PCM_OUT | PCM_MMAP | PCM_NOIRQ | PCM_MONOTONIC), &out->config);
+    if (out->pcm == NULL || !pcm_is_ready(out->pcm)) {
+        step = "open";
+        ret = -ENODEV;
+        goto exit;
+    }
+    ret = pcm_mmap_begin(out->pcm, &info->shared_memory_address, &offset1, &frames1);
+    if (ret < 0)  {
+        step = "begin";
+        goto exit;
+    }
+    info->buffer_size_frames = pcm_get_buffer_size(out->pcm);
+    info->burst_size_frames = out->config.period_size;
+    info->shared_memory_fd = pcm_get_poll_fd(out->pcm);
+
+    memset(info->shared_memory_address, 0, pcm_frames_to_bytes(out->pcm,
+                                                                info->buffer_size_frames));
+
+    ret = pcm_mmap_commit(out->pcm, 0, MMAP_PERIOD_SIZE);
+    if (ret < 0) {
+        step = "commit";
+        goto exit;
+    }
+
+    out->standby = false;
+    ret = 0;
+
+    ALOGV("%s: got mmap buffer address %p info->buffer_size_frames %d",
+          __func__, info->shared_memory_address, info->buffer_size_frames);
+
+exit:
+    if (ret != 0) {
+        if (out->pcm == NULL) {
+            ALOGE("%s: %s - %d", __func__, step, ret);
+        } else {
+            ALOGE("%s: %s %s", __func__, step, pcm_get_error(out->pcm));
+            pcm_close(out->pcm);
+            out->pcm = NULL;
+        }
+    }
+    pthread_mutex_unlock(&adev->lock);
+    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;
+    ALOGVV("%s", __func__);
+    if (position == NULL) {
+        return -EINVAL;
+    }
+    if (out->usecase != USECASE_AUDIO_PLAYBACK_MMAP) {
+        return -ENOSYS;
+    }
+    if (out->pcm == NULL) {
+        return -ENOSYS;
+    }
+
+    struct timespec ts = { 0, 0 };
+    int ret = pcm_mmap_get_hw_ptr(out->pcm, (unsigned int *)&position->position_frames, &ts);
+    if (ret < 0) {
+        ALOGE("%s: %s", __func__, pcm_get_error(out->pcm));
+        return ret;
+    }
+    position->time_nanoseconds = audio_utils_ns_from_timespec(&ts);
+    return 0;
+}
+
+
 /** audio_stream_in implementation **/
 static uint32_t in_get_sample_rate(const struct audio_stream *stream)
 {
@@ -2556,6 +2716,8 @@
     struct stream_in *in = (struct stream_in *)stream;
     struct audio_device *adev = in->dev;
     int status = 0;
+    bool do_stop = true;
+
     ALOGV("%s: enter", __func__);
 
     lock_input_stream(in);
@@ -2572,13 +2734,19 @@
 
         pthread_mutex_lock(&adev->lock);
         in->standby = true;
+        if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
+            do_stop = in->capture_started;
+            in->capture_started = false;
+        }
         if (in->pcm) {
             pcm_close(in->pcm);
             in->pcm = NULL;
         }
         adev->enable_voicerx = false;
         platform_set_echo_reference(adev, false, AUDIO_DEVICE_NONE );
-        status = stop_input_stream(in);
+        if (do_stop) {
+            status = stop_input_stream(in);
+        }
         pthread_mutex_unlock(&adev->lock);
     }
     pthread_mutex_unlock(&in->lock);
@@ -2626,7 +2794,11 @@
             /* If recording is in progress, change the tx device to new device */
             if (!in->standby) {
                 ALOGV("update input routing change");
-                in->routing_change = true;
+                // inform adm before actual routing to prevent glitches.
+                if (adev->adm_on_routing_change) {
+                    adev->adm_on_routing_change(adev->adm_data,
+                                                in->capture_handle);
+                }
                 select_devices(adev, in->usecase);
             }
         }
@@ -2648,7 +2820,7 @@
 
 static int in_set_gain(struct audio_stream_in *stream __unused, float gain __unused)
 {
-    return 0;
+    return -ENOSYS;
 }
 
 static void in_snd_mon_cb(void * stream, struct str_parms * parms)
@@ -2699,13 +2871,18 @@
     lock_input_stream(in);
 
     if (in->is_st_session) {
-        ALOGVV(" %s: reading on st session bytes=%d", __func__, bytes);
+        ALOGVV(" %s: reading on st session bytes=%zu", __func__, bytes);
         /* Read from sound trigger HAL */
         audio_extn_sound_trigger_read(in, buffer, bytes);
         pthread_mutex_unlock(&in->lock);
         return bytes;
     }
 
+    if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
+        ret = -ENOSYS;
+        goto exit;
+    }
+
     if (in->standby) {
         pthread_mutex_lock(&adev->lock);
         ret = start_input_stream(in);
@@ -2866,6 +3043,153 @@
     return add_remove_audio_effect(stream, effect, false);
 }
 
+static int in_stop(const struct audio_stream_in* stream)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+    struct audio_device *adev = in->dev;
+
+    int ret = -ENOSYS;
+    ALOGV("%s", __func__);
+    pthread_mutex_lock(&adev->lock);
+    if (in->usecase == USECASE_AUDIO_RECORD_MMAP && !in->standby &&
+            in->capture_started && in->pcm != NULL) {
+        pcm_stop(in->pcm);
+        ret = stop_input_stream(in);
+        in->capture_started = false;
+    }
+    pthread_mutex_unlock(&adev->lock);
+    return ret;
+}
+
+static int in_start(const struct audio_stream_in* stream)
+{
+    struct stream_in *in = (struct stream_in *)stream;
+    struct audio_device *adev = in->dev;
+    int ret = -ENOSYS;
+
+    ALOGV("%s in %p", __func__, in);
+    pthread_mutex_lock(&adev->lock);
+    if (in->usecase == USECASE_AUDIO_RECORD_MMAP && !in->standby &&
+            !in->capture_started && in->pcm != NULL) {
+        if (!in->capture_started) {
+            ret = start_input_stream(in);
+            if (ret == 0) {
+                in->capture_started = true;
+            }
+        }
+    }
+    pthread_mutex_unlock(&adev->lock);
+    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->dev;
+    int ret = 0;
+    unsigned int offset1;
+    unsigned int frames1;
+    const char *step = "";
+
+    pthread_mutex_lock(&adev->lock);
+    ALOGV("%s in %p", __func__, in);
+
+    if (info == NULL || min_size_frames == 0) {
+        ALOGE("%s invalid argument info %p min_size_frames %d", __func__, info, min_size_frames);
+        ret = -EINVAL;
+        goto exit;
+    }
+    if (in->usecase != USECASE_AUDIO_RECORD_MMAP || !in->standby) {
+        ALOGE("%s: usecase = %d, standby = %d", __func__, in->usecase, in->standby);
+        ALOGV("%s in %p", __func__, in);
+        ret = -ENOSYS;
+        goto exit;
+    }
+    in->pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE);
+    if (in->pcm_device_id < 0) {
+        ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
+              __func__, in->pcm_device_id, in->usecase);
+        ret = -EINVAL;
+        goto exit;
+    }
+
+    adjust_mmap_period_count(&in->config, min_size_frames);
+
+    ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
+          __func__, adev->snd_card, in->pcm_device_id, in->config.channels);
+    in->pcm = pcm_open(adev->snd_card, in->pcm_device_id,
+                        (PCM_IN | PCM_MMAP | PCM_NOIRQ | PCM_MONOTONIC), &in->config);
+    if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
+        step = "open";
+        ret = -ENODEV;
+        goto exit;
+    }
+
+    ret = pcm_mmap_begin(in->pcm, &info->shared_memory_address, &offset1, &frames1);
+    if (ret < 0)  {
+        step = "begin";
+        goto exit;
+    }
+    info->buffer_size_frames = pcm_get_buffer_size(in->pcm);
+    info->burst_size_frames = in->config.period_size;
+    info->shared_memory_fd = pcm_get_poll_fd(in->pcm);
+
+    memset(info->shared_memory_address, 0, pcm_frames_to_bytes(in->pcm,
+                                                                info->buffer_size_frames));
+
+    ret = pcm_mmap_commit(in->pcm, 0, MMAP_PERIOD_SIZE);
+    if (ret < 0) {
+        step = "commit";
+        goto exit;
+    }
+
+    in->standby = false;
+    ret = 0;
+
+    ALOGV("%s: got mmap buffer address %p info->buffer_size_frames %d",
+          __func__, info->shared_memory_address, info->buffer_size_frames);
+
+exit:
+    if (ret != 0) {
+        if (in->pcm == NULL) {
+            ALOGE("%s: %s - %d", __func__, step, ret);
+        } else {
+            ALOGE("%s: %s %s", __func__, step, pcm_get_error(in->pcm));
+            pcm_close(in->pcm);
+            in->pcm = NULL;
+        }
+    }
+    pthread_mutex_unlock(&adev->lock);
+    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;
+    ALOGVV("%s", __func__);
+    if (position == NULL) {
+        return -EINVAL;
+    }
+    if (in->usecase != USECASE_AUDIO_RECORD_MMAP) {
+        return -ENOSYS;
+    }
+    if (in->pcm == NULL) {
+        return -ENOSYS;
+    }
+    struct timespec ts = { 0, 0 };
+    int ret = pcm_mmap_get_hw_ptr(in->pcm, (unsigned int *)&position->position_frames, &ts);
+    if (ret < 0) {
+        ALOGE("%s: %s", __func__, pcm_get_error(in->pcm));
+        return ret;
+    }
+    position->time_nanoseconds = audio_utils_ns_from_timespec(&ts);
+    return 0;
+}
+
+
 static int adev_open_output_stream(struct audio_hw_device *dev,
                                    audio_io_handle_t handle,
                                    audio_devices_t devices,
@@ -3012,8 +3336,14 @@
         } else if (out->flags & AUDIO_OUTPUT_FLAG_RAW) {
             out->usecase = USECASE_AUDIO_PLAYBACK_ULL;
             out->realtime = may_use_noirq_mode(adev, USECASE_AUDIO_PLAYBACK_ULL, out->flags);
-            out->usecase = USECASE_AUDIO_PLAYBACK_ULL;
             out->config = out->realtime ? pcm_config_rt : pcm_config_low_latency;
+        } else if (out->flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
+            out->usecase = USECASE_AUDIO_PLAYBACK_MMAP;
+            out->config = pcm_config_mmap_playback;
+            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 {
             out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY;
             out->config = pcm_config_low_latency;
@@ -3081,7 +3411,11 @@
     out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
     out->stream.get_presentation_position = out_get_presentation_position;
 
-    out->af_period_multiplier  = out->realtime ? af_period_multiplier : 1;
+    if (out->realtime)
+        out->af_period_multiplier = af_period_multiplier;
+    else
+        out->af_period_multiplier = 1;
+
     out->standby = 1;
     /* out->muted = false; by calloc() */
     /* out->written = 0; by calloc() */
@@ -3094,6 +3428,23 @@
     config->channel_mask = out->stream.common.get_channels(&out->stream.common);
     config->sample_rate = out->stream.common.get_sample_rate(&out->stream.common);
 
+    out->error_log = error_log_create(
+            ERROR_LOG_ENTRIES,
+            1000000000 /* aggregate consecutive identical errors within one second in ns */);
+
+    // power_log may be null if the format is not supported
+    // or not a userdebug or eng build.
+    if (is_userdebug_or_eng_build()) {
+        const size_t POWER_LOG_FRAMES_PER_ENTRY =
+                (long long)config->sample_rate * POWER_LOG_SAMPLING_INTERVAL_MS / 1000;
+
+        out->power_log = power_log_create(
+                config->sample_rate,
+                audio_channel_count_from_out_mask(config->channel_mask),
+                config->format,
+                POWER_LOG_ENTRIES,
+                POWER_LOG_FRAMES_PER_ENTRY);
+    }
 
     /*
        By locking output stream before registering, we allow the callback
@@ -3108,6 +3459,7 @@
     pthread_mutex_unlock(&out->lock);
 
     *stream_out = &out->stream;
+
     ALOGV("%s: exit", __func__);
     return 0;
 
@@ -3140,6 +3492,12 @@
     if (adev->voice_tx_output == out)
         adev->voice_tx_output = NULL;
 
+    power_log_destroy(out->power_log);
+    out->power_log = NULL;
+
+    error_log_destroy(out->error_log);
+    out->error_log = NULL;
+
     pthread_cond_destroy(&out->cond);
     pthread_mutex_destroy(&out->lock);
     free(stream);
@@ -3211,6 +3569,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);
@@ -3438,40 +3833,57 @@
 
         in->usecase = USECASE_AUDIO_RECORD_AFE_PROXY;
         in->config = pcm_config_afe_proxy_record;
+        in->af_period_multiplier = 1;
     } else {
         in->usecase = USECASE_AUDIO_RECORD;
         if (config->sample_rate == LOW_LATENCY_CAPTURE_SAMPLE_RATE &&
-                (flags & AUDIO_INPUT_FLAG_FAST) != 0) {
+                (in->flags & AUDIO_INPUT_FLAG_FAST) != 0) {
             is_low_latency = true;
 #if LOW_LATENCY_CAPTURE_USE_CASE
             in->usecase = USECASE_AUDIO_RECORD_LOW_LATENCY;
 #endif
             in->realtime = may_use_noirq_mode(adev, in->usecase, in->flags);
-        }
-
-        in->config = in->realtime ? pcm_config_audio_capture_rt :
-                                  pcm_config_audio_capture;
-
-        if (config->format == AUDIO_FORMAT_PCM_8_24_BIT)
-            in->config.format = PCM_FORMAT_S24_LE;
-
-        if (!in->realtime) {
+            if (!in->realtime) {
+                in->config = pcm_config_audio_capture;
+                frame_size = audio_stream_in_frame_size(&in->stream);
+                buffer_size = get_input_buffer_size(config->sample_rate,
+                                                    config->format,
+                                                    channel_count,
+                                                   is_low_latency);
+                in->config.period_size = buffer_size / frame_size;
+                in->config.rate = config->sample_rate;
+                in->af_period_multiplier = 1;
+            } else {
+                // period size is left untouched for rt mode playback
+                in->config = pcm_config_audio_capture_rt;
+                in->af_period_multiplier = af_period_multiplier;
+            }
+        } else if ((config->sample_rate == LOW_LATENCY_CAPTURE_SAMPLE_RATE) &&
+                ((in->flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0)) {
+            in->usecase = USECASE_AUDIO_RECORD_MMAP;
+            in->config = pcm_config_mmap_capture;
+            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;
+            in->af_period_multiplier = 1;
+            ALOGV("%s: USECASE_AUDIO_RECORD_MMAP", __func__);
+        } else {
+            in->config = pcm_config_audio_capture;
             frame_size = audio_stream_in_frame_size(&in->stream);
             buffer_size = get_input_buffer_size(config->sample_rate,
                                                 config->format,
                                                 channel_count,
                                                 is_low_latency);
             in->config.period_size = buffer_size / frame_size;
-        } // period size is left untouched for rt mode playback
+            in->config.rate = config->sample_rate;
+            in->af_period_multiplier = 1;
+        }
+        if (config->format == AUDIO_FORMAT_PCM_8_24_BIT)
+            in->config.format = PCM_FORMAT_S24_LE;
     }
 
     in->config.channels = channel_count;
-    if (in->realtime) {
-        in->af_period_multiplier = af_period_multiplier;
-    } else {
-        in->config.rate = config->sample_rate;
-        in->af_period_multiplier = 1;
-    }
 
     /* This stream could be for sound trigger lab,
        get sound trigger pcm if present */
@@ -3654,9 +4066,11 @@
     if (!adev)
         return 0;
 
+    audio_extn_snd_mon_unregister_listener(adev);
+    audio_extn_snd_mon_deinit();
+
     audio_extn_tfa_98xx_deinit();
 
-    audio_extn_snd_mon_unregister_listener(adev);
     pthread_mutex_lock(&adev_init_lock);
 
     if ((--audio_device_ref_count) == 0) {
@@ -3762,6 +4176,7 @@
     adev->device.open_output_stream = adev_open_output_stream;
     adev->device.close_output_stream = adev_close_output_stream;
     adev->device.open_input_stream = adev_open_input_stream;
+
     adev->device.close_input_stream = adev_close_input_stream;
     adev->device.dump = adev_dump;
 
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index 2cf72e1..ca068e2 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -25,15 +25,17 @@
 #include <tinycompress/tinycompress.h>
 
 #include <audio_route/audio_route.h>
+#include <audio_utils/ErrorLog.h>
+#include <audio_utils/PowerLog.h>
 #include "voice.h"
 
 // dlopen() does not go through default library path search if there is a "/" in the library name.
 #ifdef __LP64__
-#define VISUALIZER_LIBRARY_PATH "/system/lib64/soundfx/libqcomvisualizer.so"
-#define OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH "/system/lib64/soundfx/libqcompostprocbundle.so"
+#define VISUALIZER_LIBRARY_PATH "/vendor/lib64/soundfx/libqcomvisualizer.so"
+#define OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH "/vendor/lib64/soundfx/libqcompostprocbundle.so"
 #else
-#define VISUALIZER_LIBRARY_PATH "/system/lib/soundfx/libqcomvisualizer.so"
-#define OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH "/system/lib/soundfx/libqcompostprocbundle.so"
+#define VISUALIZER_LIBRARY_PATH "/vendor/lib/soundfx/libqcomvisualizer.so"
+#define OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH "/vendor/lib/soundfx/libqcompostprocbundle.so"
 #endif
 #define ADM_LIBRARY_PATH "libadm.so"
 
@@ -49,10 +51,23 @@
 #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
 
+#define POWER_LOG_LINES 40
+#define POWER_LOG_SAMPLING_INTERVAL_MS 50
+#define POWER_LOG_ENTRIES (1 /* minutes */ * 60 /* seconds */ * 1000 /* msec */ \
+                           / POWER_LOG_SAMPLING_INTERVAL_MS)
+
+/* Error types for the error log */
+enum {
+    ERROR_CODE_STANDBY = 1,
+    ERROR_CODE_WRITE,
+};
+
 typedef enum card_status_t {
     CARD_STATUS_OFFLINE,
     CARD_STATUS_ONLINE
@@ -71,6 +86,7 @@
     USECASE_AUDIO_PLAYBACK_OFFLOAD,
     USECASE_AUDIO_PLAYBACK_TTS,
     USECASE_AUDIO_PLAYBACK_ULL,
+    USECASE_AUDIO_PLAYBACK_MMAP,
 
     /* HFP Use case*/
     USECASE_AUDIO_HFP_SCO,
@@ -79,6 +95,7 @@
     /* Capture usecases */
     USECASE_AUDIO_RECORD,
     USECASE_AUDIO_RECORD_LOW_LATENCY,
+    USECASE_AUDIO_RECORD_MMAP,
 
     /* Voice extension usecases
      *
@@ -150,24 +167,6 @@
     int data[];
 };
 
-enum {
-    ERROR_CODE_STANDBY,
-    ERROR_CODE_WRITE,
-};
-
-struct error_log_entry {
-    int32_t code;
-    int32_t count;
-    int64_t first_time;
-    int64_t last_time;
-};
-
-struct error_log {
-    uint32_t errors;
-    uint32_t idx;
-    struct error_log_entry entries[ERROR_LOG_ENTRIES];
-};
-
 struct stream_out {
     struct audio_stream_out stream;
     pthread_mutex_t lock; /* see note below on mutex acquisition order */
@@ -205,13 +204,11 @@
     int send_new_metadata;
     bool realtime;
     int af_period_multiplier;
-    bool routing_change;
     struct audio_device *dev;
     card_status_t card_status;
 
-    struct error_log error_log;
-
-    int64_t last_write_time_us;
+    error_log_t *error_log;
+    power_log_t *power_log;
 };
 
 struct stream_in {
@@ -236,10 +233,10 @@
     bool is_st_session_active;
     bool realtime;
     int af_period_multiplier;
-    bool routing_change;
     struct audio_device *dev;
     audio_format_t format;
     card_status_t card_status;
+    int capture_started;
 };
 
 typedef enum usecase_type_t {
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 4995bd8..2fe6168 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -969,7 +969,7 @@
             ALOGE("%s: Could not find the symbol acdb_loader_deallocate_ACDB from %s",
                   __func__, LIB_ACDB_LOADER);
 
-        my_data->acdb_send_audio_cal_v3 = (acdb_send_audio_cal_t)dlsym(my_data->acdb_handle,
+        my_data->acdb_send_audio_cal_v3 = (acdb_send_audio_cal_v3_t)dlsym(my_data->acdb_handle,
                                                     "acdb_loader_send_audio_cal_v3");
         if (!my_data->acdb_send_audio_cal_v3)
             ALOGE("%s: Could not find the symbol acdb_send_audio_cal from %s",
@@ -1054,6 +1054,7 @@
         free(info_item);
     }
 
+    mixer_close(my_data->adev->mixer);
     free(platform);
 }
 
@@ -1073,7 +1074,7 @@
 {
     struct platform_data *my_data = (struct platform_data *)platform;
 
-    if (platform == NULL || device_name == NULL) {
+    if (platform == NULL) {
         ALOGW("%s: something wrong, use legacy get_snd_device name", __func__);
         strlcpy(device_name, platform_get_snd_device_name(snd_device),
                  DEVICE_NAME_MAX_SIZE);
@@ -1093,9 +1094,16 @@
     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)
+                                              snd_device_t snd_device __unused)
 {
     return false;
 }
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index 7b76df3..072a1e4 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -1099,10 +1099,18 @@
                                       snd_device_t snd_device,
                                       char *device_name)
 {
-    device_name = platform_get_snd_device_name(snd_device);
+    strlcpy(device_name, platform_get_snd_device_name(snd_device),
+            DEVICE_NAME_MAX_SIZE);
     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 5aaf93a..0f3bcf0 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2016 The Android Open Source Project
+ * Copyright (C) 2013-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.
@@ -28,8 +28,8 @@
 #include "audio_extn.h"
 #include <linux/msm_audio.h>
 
-#define MIXER_XML_DEFAULT_PATH "/system/etc/mixer_paths.xml"
-#define MIXER_XML_BASE_STRING "/system/etc/mixer_paths"
+#define MIXER_XML_DEFAULT_PATH "mixer_paths.xml"
+#define MIXER_XML_BASE_STRING "mixer_paths"
 #define TOMTOM_8226_SND_CARD_NAME "msm8226-tomtom-snd-card"
 #define TOMTOM_MIXER_FILE_SUFFIX "wcd9330"
 
@@ -120,7 +120,7 @@
     bool speaker_lr_swap;
 
     void *acdb_handle;
-#if defined (PLATFORM_MSM8994) || (PLATFORM_MSM8996)
+#if defined (PLATFORM_MSM8994) || (PLATFORM_MSM8996) || (PLATFORM_MSM8998)
     acdb_init_v2_cvd_t acdb_init;
 #elif defined (PLATFORM_MSM8084)
     acdb_init_v2_t acdb_init;
@@ -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;
@@ -158,12 +159,17 @@
                                         MULTIMEDIA2_PCM_DEVICE},
     [USECASE_AUDIO_PLAYBACK_ULL] = {MULTIMEDIA3_PCM_DEVICE,
                                     MULTIMEDIA3_PCM_DEVICE},
+    [USECASE_AUDIO_PLAYBACK_MMAP] = {MMAP_PLAYBACK_PCM_DEVICE,
+            MMAP_PLAYBACK_PCM_DEVICE},
 
     [USECASE_AUDIO_RECORD] = {AUDIO_RECORD_PCM_DEVICE,
                               AUDIO_RECORD_PCM_DEVICE},
     [USECASE_AUDIO_RECORD_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
                                           LOWLATENCY_PCM_DEVICE},
 
+    [USECASE_AUDIO_RECORD_MMAP] = {MMAP_RECORD_PCM_DEVICE,
+            MMAP_RECORD_PCM_DEVICE},
+
     [USECASE_VOICE_CALL] = {VOICE_CALL_PCM_DEVICE,
                             VOICE_CALL_PCM_DEVICE},
     [USECASE_VOICE2_CALL] = {VOICE2_CALL_PCM_DEVICE, VOICE2_CALL_PCM_DEVICE},
@@ -221,10 +227,17 @@
     [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = "voice-tty-full-headphones",
     [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_TTY_FULL_USB] = "voice-tty-full-usb",
+    [SND_DEVICE_OUT_VOICE_TTY_VCO_USB] = "voice-tty-vco-usb",
     [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",
+    [SND_DEVICE_OUT_SPEAKER_AND_BT_SCO] = "speaker-and-bt-sco",
+    [SND_DEVICE_OUT_SPEAKER_AND_BT_SCO_WB] = "speaker-and-bt-sco-wb",
 
     /* Capture sound devices */
     [SND_DEVICE_IN_HANDSET_MIC] = "handset-mic",
@@ -266,6 +279,8 @@
     [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = "voice-tty-full-headset-mic",
     [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = "voice-tty-vco-handset-mic",
     [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = "voice-tty-hco-headset-mic",
+    [SND_DEVICE_IN_VOICE_TTY_FULL_USB_MIC] = "voice-tty-full-usb-mic",
+    [SND_DEVICE_IN_VOICE_TTY_HCO_USB_MIC] = "voice-tty-hco-usb-mic",
 
     [SND_DEVICE_IN_VOICE_REC_MIC] = "voice-rec-mic",
     [SND_DEVICE_IN_VOICE_REC_MIC_NS] = "voice-rec-mic",
@@ -273,6 +288,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",
@@ -318,7 +334,12 @@
     [SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES] = 17,
     [SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES] = 17,
     [SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET] = 37,
+    [SND_DEVICE_OUT_VOICE_TTY_FULL_USB] = 17,
+    [SND_DEVICE_OUT_VOICE_TTY_VCO_USB] = 17,
     [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,
@@ -362,6 +383,8 @@
     [SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC] = 16,
     [SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC] = 36,
     [SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC] = 16,
+    [SND_DEVICE_IN_VOICE_TTY_FULL_USB_MIC] = 16,
+    [SND_DEVICE_IN_VOICE_TTY_HCO_USB_MIC] = 16,
 
     [SND_DEVICE_IN_VOICE_REC_MIC] = ACDB_ID_VOICE_REC_MIC,
     [SND_DEVICE_IN_VOICE_REC_MIC_NS] = 113,
@@ -378,7 +401,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,
@@ -388,6 +411,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;
@@ -422,10 +448,17 @@
     {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)},
-
-    /* in */
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_BT_SCO)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_AND_BT_SCO_WB)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_TTY_FULL_USB)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_TTY_VCO_USB)},
+    {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)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_SPEAKER_PROTECTED)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED)},
+
+    /* in */
     {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC)},
     {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC_AEC)},
     {TO_NAME_INDEX(SND_DEVICE_IN_HANDSET_MIC_NS)},
@@ -465,6 +498,9 @@
     {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC)},
     {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC)},
     {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_TTY_FULL_USB_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_TTY_HCO_USB_MIC)},
+
 
     {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_REC_MIC)},
     {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_REC_MIC_NS)},
@@ -473,6 +509,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)},
@@ -499,24 +536,32 @@
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD)},
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_TTS)},
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_ULL)},
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_MMAP)},
     {TO_NAME_INDEX(USECASE_AUDIO_RECORD)},
     {TO_NAME_INDEX(USECASE_AUDIO_RECORD_LOW_LATENCY)},
+    {TO_NAME_INDEX(USECASE_AUDIO_RECORD_MMAP)},
     {TO_NAME_INDEX(USECASE_VOICE_CALL)},
     {TO_NAME_INDEX(USECASE_VOICE2_CALL)},
     {TO_NAME_INDEX(USECASE_VOLTE_CALL)},
     {TO_NAME_INDEX(USECASE_QCHAT_CALL)},
     {TO_NAME_INDEX(USECASE_VOWLAN_CALL)},
+    {TO_NAME_INDEX(USECASE_VOICEMMODE1_CALL)},
+    {TO_NAME_INDEX(USECASE_VOICEMMODE2_CALL)},
     {TO_NAME_INDEX(USECASE_INCALL_REC_UPLINK)},
     {TO_NAME_INDEX(USECASE_INCALL_REC_DOWNLINK)},
     {TO_NAME_INDEX(USECASE_INCALL_REC_UPLINK_AND_DOWNLINK)},
     {TO_NAME_INDEX(USECASE_AUDIO_HFP_SCO)},
-    {TO_NAME_INDEX(USECASE_VOICEMMODE1_CALL)},
-    {TO_NAME_INDEX(USECASE_VOICEMMODE2_CALL)},
+    {TO_NAME_INDEX(USECASE_AUDIO_SPKR_CALIB_RX)},
+    {TO_NAME_INDEX(USECASE_AUDIO_SPKR_CALIB_TX)},
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_AFE_PROXY)},
+    {TO_NAME_INDEX(USECASE_AUDIO_RECORD_AFE_PROXY)},
+    {TO_NAME_INDEX(USECASE_AUDIO_DSM_FEEDBACK)},
 };
 
 #define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL)
 #define LOW_LATENCY_PLATFORM_DELAY (13*1000LL)
-#define ULL_PLATFORM_DELAY         (7*1000LL)
+#define ULL_PLATFORM_DELAY         (3*1000LL)
+#define MMAP_PLATFORM_DELAY        (3*1000LL)
 
 static pthread_once_t check_op_once_ctl = PTHREAD_ONCE_INIT;
 static bool is_tmus = false;
@@ -890,6 +935,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");
@@ -902,6 +951,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");
@@ -925,6 +979,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");
@@ -974,7 +1031,7 @@
         return 0;
     }
 
-#if defined (PLATFORM_MSM8994) || (PLATFORM_MSM8996)
+#if defined (PLATFORM_MSM8994) || (PLATFORM_MSM8996) || (PLATFORM_MSM8998)
     char *cvd_version = calloc(1, MAX_CVD_VERSION_STRING_SIZE);
     if (!cvd_version)
         ALOGE("failed to allocate cvd_version");
@@ -992,6 +1049,79 @@
     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");
+}
+
+// Treblized config files will be located in /odm/etc or /vendor/etc.
+static const char *kConfigLocationList[] =
+        {"/odm/etc", "/vendor/etc", "/system/etc"};
+static const int kConfigLocationListSize =
+        (sizeof(kConfigLocationList) / sizeof(kConfigLocationList[0]));
+
+bool resolveConfigFile(char file_name[MIXER_PATH_MAX_LENGTH]) {
+    char full_config_path[MIXER_PATH_MAX_LENGTH];
+    for (int i = 0; i < kConfigLocationListSize; i++) {
+        snprintf(full_config_path,
+                 MIXER_PATH_MAX_LENGTH,
+                 "%s/%s",
+                 kConfigLocationList[i],
+                 file_name);
+        if (F_OK == access(full_config_path, 0)) {
+            strcpy(file_name, full_config_path);
+            return true;
+        }
+    }
+    return false;
+}
+
 void *platform_init(struct audio_device *adev)
 {
     char value[PROPERTY_VALUE_MAX];
@@ -1075,15 +1205,15 @@
             snprintf(mixer_xml_file, sizeof(mixer_xml_file), "%s_%s_%s.xml",
                              MIXER_XML_BASE_STRING, snd_split_handle->snd_card,
                              snd_split_handle->form_factor);
-
-            if (F_OK != access(mixer_xml_file, 0)) {
+            if (!resolveConfigFile(mixer_xml_file)) {
                 memset(mixer_xml_file, 0, sizeof(mixer_xml_file));
                 snprintf(mixer_xml_file, sizeof(mixer_xml_file), "%s_%s.xml",
                              MIXER_XML_BASE_STRING, snd_split_handle->snd_card);
 
-                if (F_OK != access(mixer_xml_file, 0)) {
+                if (!resolveConfigFile(mixer_xml_file)) {
                     memset(mixer_xml_file, 0, sizeof(mixer_xml_file));
                     strlcpy(mixer_xml_file, MIXER_XML_DEFAULT_PATH, MIXER_PATH_MAX_LENGTH);
+                    resolveConfigFile(mixer_xml_file);
                 }
             }
 
@@ -1091,14 +1221,15 @@
                              PLATFORM_INFO_XML_BASE_STRING, snd_split_handle->snd_card,
                              snd_split_handle->form_factor);
 
-            if (F_OK != access(platform_info_file, 0)) {
+            if (!resolveConfigFile(platform_info_file)) {
                 memset(platform_info_file, 0, sizeof(platform_info_file));
                 snprintf(platform_info_file, sizeof(platform_info_file), "%s_%s.xml",
                              PLATFORM_INFO_XML_BASE_STRING, snd_split_handle->snd_card);
 
-                if (F_OK != access(platform_info_file, 0)) {
+                if (!resolveConfigFile(platform_info_file)) {
                     memset(platform_info_file, 0, sizeof(platform_info_file));
                     strlcpy(platform_info_file, PLATFORM_INFO_XML_PATH, MIXER_PATH_MAX_LENGTH);
+                    resolveConfigFile(platform_info_file);
                 }
             }
         }
@@ -1253,7 +1384,7 @@
             ALOGV("%s: Could not find the symbol acdb_loader_send_gain_dep_cal from %s",
                   __func__, LIB_ACDB_LOADER);
 
-#if defined (PLATFORM_MSM8994) || (PLATFORM_MSM8996)
+#if defined (PLATFORM_MSM8994) || (PLATFORM_MSM8996) || (PLATFORM_MSM8998)
         acdb_init_v2_cvd_t acdb_init;
         acdb_init = (acdb_init_v2_cvd_t)dlsym(my_data->acdb_handle,
                                               "acdb_loader_init_v2");
@@ -1290,6 +1421,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);
@@ -1297,6 +1431,8 @@
     /* load csd client */
     platform_csd_init(my_data);
 
+    platform_backend_config_init(my_data);
+
     return my_data;
 
 init_failed:
@@ -1347,7 +1483,11 @@
         free(info_item);
     }
 
+    mixer_close(my_data->adev->mixer);
     free(platform);
+
+    /* deinit usb */
+    audio_extn_usb_deinit();
 }
 
 const char *platform_get_snd_device_name(snd_device_t snd_device)
@@ -1366,9 +1506,10 @@
 {
     struct platform_data *my_data = (struct platform_data *)platform;
 
-    if (platform == NULL || device_name == NULL) {
+    if (platform == NULL) {
         ALOGW("%s: something wrong, use legacy get_snd_device name", __func__);
-        device_name = platform_get_snd_device_name(snd_device);
+        strlcpy(device_name, platform_get_snd_device_name(snd_device),
+                DEVICE_NAME_MAX_SIZE);
     } else if (snd_device >= SND_DEVICE_MIN && snd_device < SND_DEVICE_MAX) {
         if (operator_specific_device_table[snd_device] != NULL) {
             strlcpy(device_name, get_operator_specific_device_mixer_path(snd_device),
@@ -1527,8 +1668,8 @@
     return ret;
 }
 
-int platform_get_default_app_type_v2(void *platform, usecase_type_t type __unused,
-                                     int *app_type)
+int platform_get_default_app_type_v2(void *platform __unused, usecase_type_t type __unused,
+                                     int *app_type __unused)
 {
     ALOGE("%s: Not implemented", __func__);
     return -ENOSYS;
@@ -1547,6 +1688,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;
@@ -1910,6 +2083,26 @@
         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_BT_SCO &&
+               !platform_check_backends_match(SND_DEVICE_OUT_SPEAKER,
+                                              SND_DEVICE_OUT_BT_SCO)) {
+        *num_devices = 2;
+        new_snd_devices[0] = SND_DEVICE_OUT_SPEAKER;
+        new_snd_devices[1] = SND_DEVICE_OUT_BT_SCO;
+        ret = 0;
+    } else if (snd_device == SND_DEVICE_OUT_SPEAKER_AND_BT_SCO_WB &&
+               !platform_check_backends_match(SND_DEVICE_OUT_SPEAKER,
+                                              SND_DEVICE_OUT_BT_SCO_WB)) {
+        *num_devices = 2;
+        new_snd_devices[0] = SND_DEVICE_OUT_SPEAKER;
+        new_snd_devices[1] = SND_DEVICE_OUT_BT_SCO_WB;
+        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;
 }
@@ -1948,6 +2141,14 @@
         } 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_ALL_SCO) &&
+                   ((devices & ~AUDIO_DEVICE_OUT_ALL_SCO) == AUDIO_DEVICE_OUT_SPEAKER)) {
+            snd_device = adev->bt_wb_speech_enabled ?
+                    SND_DEVICE_OUT_SPEAKER_AND_BT_SCO_WB :
+                    SND_DEVICE_OUT_SPEAKER_AND_BT_SCO;
+        } 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;
@@ -1981,6 +2182,24 @@
                 else
                     snd_device = SND_DEVICE_OUT_VOICE_HEADPHONES;
                 }
+        } else if (devices & AUDIO_DEVICE_OUT_USB_DEVICE) {
+            if (voice_is_in_call(adev)) {
+                switch (adev->voice.tty_mode) {
+                    case TTY_MODE_FULL:
+                        snd_device = SND_DEVICE_OUT_VOICE_TTY_FULL_USB;
+                        break;
+                    case TTY_MODE_VCO:
+                        snd_device = SND_DEVICE_OUT_VOICE_TTY_VCO_USB;
+                        break;
+                    case TTY_MODE_HCO:
+                        // since Hearing will be on handset\speaker, use existing device
+                        snd_device = SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET;
+                        break;
+                    default:
+                        ALOGE("%s: Invalid TTY mode (%#x)",
+                              __func__, adev->voice.tty_mode);
+                }
+            }
         } else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) {
             if (adev->bt_wb_speech_enabled) {
                 snd_device = SND_DEVICE_OUT_BT_SCO_WB;
@@ -2028,7 +2247,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;
@@ -2067,17 +2291,33 @@
                 out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET ||
                 out_device & AUDIO_DEVICE_OUT_LINE) {
                 switch (adev->voice.tty_mode) {
-                case TTY_MODE_FULL:
-                    snd_device = SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC;
-                    break;
-                case TTY_MODE_VCO:
-                    snd_device = SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC;
-                    break;
-                case TTY_MODE_HCO:
-                    snd_device = SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC;
-                    break;
-                default:
-                    ALOGE("%s: Invalid TTY mode (%#x)", __func__, adev->voice.tty_mode);
+                    case TTY_MODE_FULL:
+                        snd_device = SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC;
+                        break;
+                    case TTY_MODE_VCO:
+                        snd_device = SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC;
+                        break;
+                    case TTY_MODE_HCO:
+                        snd_device = SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC;
+                        break;
+                    default:
+                        ALOGE("%s: Invalid TTY mode (%#x)", __func__, adev->voice.tty_mode);
+                }
+                goto exit;
+            } else if (out_device & AUDIO_DEVICE_OUT_USB_DEVICE) {
+                switch (adev->voice.tty_mode) {
+                    case TTY_MODE_FULL:
+                        snd_device = SND_DEVICE_IN_VOICE_TTY_FULL_USB_MIC;
+                        break;
+                    case TTY_MODE_VCO:
+                        // since voice will be captured from handset mic, use existing device
+                        snd_device = SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC;
+                        break;
+                    case TTY_MODE_HCO:
+                        snd_device = SND_DEVICE_IN_VOICE_TTY_HCO_USB_MIC;
+                        break;
+                    default:
+                        ALOGE("%s: Invalid TTY mode (%#x)", __func__, adev->voice.tty_mode);
                 }
                 goto exit;
             }
@@ -2161,10 +2401,10 @@
             } else if ((channel_mask == AUDIO_CHANNEL_IN_FRONT_BACK) &&
                        (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
                 snd_device = SND_DEVICE_IN_VOICE_REC_DMIC_STEREO;
-            } else if (((int)channel_mask == AUDIO_CHANNEL_INDEX_MASK_3) &&
+            } else if ((channel_mask == AUDIO_CHANNEL_INDEX_MASK_3) &&
                        (my_data->source_mic_type & SOURCE_THREE_MIC)) {
                 snd_device = SND_DEVICE_IN_THREE_MIC;
-            } else if (((int)channel_mask == AUDIO_CHANNEL_INDEX_MASK_4) &&
+            } else if ((channel_mask == AUDIO_CHANNEL_INDEX_MASK_4) &&
                        (my_data->source_mic_type & SOURCE_QUAD_MIC)) {
                 snd_device = SND_DEVICE_IN_QUAD_MIC;
             }
@@ -2191,10 +2431,10 @@
                  (channel_mask == AUDIO_CHANNEL_IN_STEREO)) &&
                        (my_data->source_mic_type & SOURCE_DUAL_MIC)) {
                 snd_device = SND_DEVICE_IN_UNPROCESSED_STEREO_MIC;
-            } else if (((int)channel_mask == AUDIO_CHANNEL_INDEX_MASK_3) &&
+            } else if ((channel_mask == AUDIO_CHANNEL_INDEX_MASK_3) &&
                        (my_data->source_mic_type & SOURCE_THREE_MIC)) {
                 snd_device = SND_DEVICE_IN_UNPROCESSED_THREE_MIC;
-            } else if (((int)channel_mask == AUDIO_CHANNEL_INDEX_MASK_4) &&
+            } else if ((channel_mask == AUDIO_CHANNEL_INDEX_MASK_4) &&
                        (my_data->source_mic_type & SOURCE_QUAD_MIC)) {
                 snd_device = SND_DEVICE_IN_UNPROCESSED_QUAD_MIC;
             } else {
@@ -2282,10 +2522,10 @@
             !(in_device & AUDIO_DEVICE_IN_COMMUNICATION)) {
         if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
             if ((my_data->source_mic_type & SOURCE_QUAD_MIC) &&
-                (int)channel_mask == AUDIO_CHANNEL_INDEX_MASK_4) {
+                channel_mask == AUDIO_CHANNEL_INDEX_MASK_4) {
                 snd_device = SND_DEVICE_IN_QUAD_MIC;
             } else if ((my_data->source_mic_type & SOURCE_THREE_MIC) &&
-                       (int)channel_mask == AUDIO_CHANNEL_INDEX_MASK_3) {
+                       channel_mask == AUDIO_CHANNEL_INDEX_MASK_3) {
                 snd_device = SND_DEVICE_IN_THREE_MIC;
             } else if ((my_data->source_mic_type & SOURCE_DUAL_MIC) &&
                        channel_count == 2) {
@@ -2328,6 +2568,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__);
@@ -2368,6 +2610,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__);
@@ -2621,31 +2868,13 @@
             return LOW_LATENCY_PLATFORM_DELAY;
         case USECASE_AUDIO_PLAYBACK_ULL:
             return ULL_PLATFORM_DELAY;
+        case USECASE_AUDIO_PLAYBACK_MMAP:
+            return MMAP_PLATFORM_DELAY;
         default:
             return 0;
     }
 }
 
-bool platform_check_and_set_capture_backend_cfg(struct audio_device* adev,
-         struct audio_usecase *usecase, snd_device_t snd_device)
-{
-    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)
 {
@@ -2868,3 +3097,472 @@
     }
     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 void platform_pick_playback_cfg_for_uc(struct audio_device *adev,
+                                              struct audio_usecase *usecase,
+                                              snd_device_t snd_device,
+                                              unsigned int *bit_width,
+                                              unsigned int *sample_rate,
+                                              unsigned int *channels)
+{
+    int i =0;
+    struct listnode *node;
+    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);
+            ALOGV("%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;
+            }
+        }
+    }
+    return;
+}
+
+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;
+    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
+         */
+        platform_pick_playback_cfg_for_uc(adev, usecase, snd_device,
+                                          &bit_width,
+                                          &sample_rate,
+                                          &channels);
+    }
+
+    switch (backend_idx) {
+        case 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);
+            break;
+        case DEFAULT_CODEC_BACKEND:
+        case HEADPHONE_BACKEND:
+        default:
+            bit_width = platform_get_snd_device_bit_width(snd_device);
+            sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
+            channels = CODEC_BACKEND_DEFAULT_CHANNELS;
+            break;
+    }
+
+    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;
+    memset(&backend_cfg, 0, sizeof(struct audio_backend_cfg));
+
+    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 aa4c08d..b411e9d 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2016 The Android Open Source Project
+ * Copyright (C) 2013-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.
@@ -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
@@ -73,11 +82,18 @@
     SND_DEVICE_OUT_VOICE_TTY_FULL_HEADPHONES,
     SND_DEVICE_OUT_VOICE_TTY_VCO_HEADPHONES,
     SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET,
+    SND_DEVICE_OUT_VOICE_TTY_FULL_USB,
+    SND_DEVICE_OUT_VOICE_TTY_VCO_USB,
     SND_DEVICE_OUT_VOICE_HAC_HANDSET,
     SND_DEVICE_OUT_VOICE_TX,
     SND_DEVICE_OUT_SPEAKER_PROTECTED,
     SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED,
     SND_DEVICE_OUT_VOICE_SPEAKER_HFP,
+    SND_DEVICE_OUT_SPEAKER_AND_BT_SCO,
+    SND_DEVICE_OUT_SPEAKER_AND_BT_SCO_WB,
+    SND_DEVICE_OUT_USB_HEADSET,
+    SND_DEVICE_OUT_USB_HEADPHONES,
+    SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET,
     SND_DEVICE_OUT_END,
 
     /*
@@ -125,6 +141,8 @@
     SND_DEVICE_IN_VOICE_TTY_FULL_HEADSET_MIC,
     SND_DEVICE_IN_VOICE_TTY_VCO_HANDSET_MIC,
     SND_DEVICE_IN_VOICE_TTY_HCO_HEADSET_MIC,
+    SND_DEVICE_IN_VOICE_TTY_FULL_USB_MIC,
+    SND_DEVICE_IN_VOICE_TTY_HCO_USB_MIC,
 
     SND_DEVICE_IN_VOICE_REC_MIC,
     SND_DEVICE_IN_VOICE_REC_MIC_NS,
@@ -142,6 +160,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 +174,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
@@ -215,6 +252,9 @@
 
 #define MULTIMEDIA3_PCM_DEVICE 4
 
+#define MMAP_PLAYBACK_PCM_DEVICE 18
+#define MMAP_RECORD_PCM_DEVICE 18
+
 #define QUAT_MI2S_PCM_DEVICE    44
 #define PLAYBACK_OFFLOAD_DEVICE 9
 #define LOWLATENCY_PCM_DEVICE 15
@@ -313,6 +353,23 @@
     get_sample_rate_t get_sample_rate;
 };
 
-#define PLATFORM_INFO_XML_PATH          "/system/etc/audio_platform_info.xml"
-#define PLATFORM_INFO_XML_BASE_STRING   "/system/etc/audio_platform_info"
+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          "audio_platform_info.xml"
+#define PLATFORM_INFO_XML_BASE_STRING   "audio_platform_info"
 #endif // QCOM_AUDIO_PLATFORM_H
diff --git a/hal/platform_api.h b/hal/platform_api.h
index ebbe9d2..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;
@@ -28,6 +34,7 @@
 };
 
 enum card_status_t;
+struct audio_usecase;
 enum usecase_type_t;
 
 void *platform_init(struct audio_device *adev);
@@ -111,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);
 
diff --git a/legacy/libalsa-intf/alsa_pcm.c b/legacy/libalsa-intf/alsa_pcm.c
index a814ae8..84d6549 100644
--- a/legacy/libalsa-intf/alsa_pcm.c
+++ b/legacy/libalsa-intf/alsa_pcm.c
@@ -46,10 +46,6 @@
 
 #include "alsa_audio.h"
 
-#define __force
-#define __bitwise
-#define __user
-
 #define DEBUG 1
 
 enum format_alias {
diff --git a/post_proc/Android.mk b/post_proc/Android.mk
index 83f6a49..eb59ddb 100644
--- a/post_proc/Android.mk
+++ b/post_proc/Android.mk
@@ -20,6 +20,8 @@
 	libtinyalsa
 
 LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_OWNER := qcom
+LOCAL_PROPRIETARY_MODULE := true
 
 LOCAL_MODULE_RELATIVE_PATH := soundfx
 LOCAL_MODULE:= libqcompostprocbundle
@@ -37,7 +39,7 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_CFLAGS := -DLIB_AUDIO_HAL="/system/lib/hw/audio.primary."$(TARGET_BOARD_PLATFORM)".so"
+LOCAL_CFLAGS := -DLIB_AUDIO_HAL="audio.primary."$(TARGET_BOARD_PLATFORM)".so"
 
 LOCAL_SRC_FILES:= \
 	volume_listener.c
@@ -51,6 +53,8 @@
 
 LOCAL_MODULE_RELATIVE_PATH := soundfx
 LOCAL_MODULE:= libvolumelistener
+LOCAL_MODULE_OWNER := qcom
+LOCAL_PROPRIETARY_MODULE := true
 
 LOCAL_C_INCLUDES := \
         hardware/qcom/audio/hal \
diff --git a/post_proc/bass_boost.c b/post_proc/bass_boost.c
index f303886..a5c6a4a 100644
--- a/post_proc/bass_boost.c
+++ b/post_proc/bass_boost.c
@@ -31,7 +31,8 @@
         {0x0634f220, 0xddd4, 0x11db, 0xa0fc, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b }},
         {0x2c4a8c24, 0x1581, 0x487f, 0x94f6, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid
         EFFECT_CONTROL_API_VERSION,
-        (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_DEVICE_IND | EFFECT_FLAG_HW_ACC_TUNNEL),
+        (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_DEVICE_IND | EFFECT_FLAG_HW_ACC_TUNNEL |
+                EFFECT_FLAG_VOLUME_CTRL),
         0, /* TODO */
         1,
         "MSM offload bassboost",
diff --git a/post_proc/bundle.c b/post_proc/bundle.c
index df327ab..f83e231 100644
--- a/post_proc/bundle.c
+++ b/post_proc/bundle.c
@@ -244,7 +244,7 @@
 __attribute__ ((visibility ("default")))
 int offload_effects_bundle_hal_stop_output(audio_io_handle_t output, int pcm_id)
 {
-    int ret;
+    int ret = 0;
     struct listnode *node;
     struct listnode *fx_node;
     output_context_t *out_ctxt;
@@ -668,10 +668,19 @@
         if (context->ops.set_device)
             context->ops.set_device(context, device);
         } break;
-    case EFFECT_CMD_SET_VOLUME:
+    case EFFECT_CMD_SET_VOLUME: {
+        // if pReplyData is NULL, VOL_CTRL is delegated to another effect
+        if (pReplyData == NULL) {
+            break;
+        }
+        if (pCmdData == NULL || cmdSize != 2 * sizeof(uint32_t) ||
+                replySize == NULL || *replySize < 2*sizeof(int32_t)) {
+            return -EINVAL;
+        }
+        memcpy(pReplyData, pCmdData, sizeof(int32_t)*2);
+        } break;
     case EFFECT_CMD_SET_AUDIO_MODE:
         break;
-
     case EFFECT_CMD_OFFLOAD: {
         output_context_t *out_ctxt;
 
@@ -703,8 +712,6 @@
             add_effect_to_output(out_ctxt, context);
 
         } break;
-
-
     default:
         if (cmdCode >= EFFECT_CMD_FIRST_PROPRIETARY && context->ops.command)
             status = context->ops.command(context, cmdCode, cmdSize,
@@ -750,11 +757,11 @@
 
 __attribute__ ((visibility ("default")))
 audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = {
-    tag : AUDIO_EFFECT_LIBRARY_TAG,
-    version : EFFECT_LIBRARY_API_VERSION,
-    name : "Offload Effects Bundle Library",
-    implementor : "The Android Open Source Project",
-    create_effect : effect_lib_create,
-    release_effect : effect_lib_release,
-    get_descriptor : effect_lib_get_descriptor,
+    .tag = AUDIO_EFFECT_LIBRARY_TAG,
+    .version = EFFECT_LIBRARY_API_VERSION,
+    .name = "Offload Effects Bundle Library",
+    .implementor = "The Android Open Source Project",
+    .create_effect = effect_lib_create,
+    .release_effect = effect_lib_release,
+    .get_descriptor = effect_lib_get_descriptor,
 };
diff --git a/post_proc/equalizer.c b/post_proc/equalizer.c
index 4e4552f..f7d6152 100644
--- a/post_proc/equalizer.c
+++ b/post_proc/equalizer.c
@@ -31,7 +31,7 @@
         {0x0bed4300, 0xddd6, 0x11db, 0x8f34, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // type
         {0xa0dac280, 0x401c, 0x11e3, 0x9379, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid
         EFFECT_CONTROL_API_VERSION,
-        (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_HW_ACC_TUNNEL),
+        (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_HW_ACC_TUNNEL | EFFECT_FLAG_VOLUME_CTRL),
         0, /* TODO */
         1,
         "MSM offload equalizer",
@@ -183,7 +183,7 @@
 
 int equalizer_get_num_presets(equalizer_context_t *context __unused)
 {
-    ALOGV("%s: presets_num: %d", __func__,
+    ALOGV("%s: presets_num: %zu", __func__,
            sizeof(equalizer_preset_names)/sizeof(char *));
     return sizeof(equalizer_preset_names)/sizeof(char *);
 }
diff --git a/post_proc/reverb.c b/post_proc/reverb.c
index e5fc950..be4d566 100644
--- a/post_proc/reverb.c
+++ b/post_proc/reverb.c
@@ -32,7 +32,7 @@
         { 0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac, { 0x4e, 0x23, 0x4d, 0x06, 0x83, 0x9e } },
         { 0x79a18026, 0x18fd, 0x4185, 0x8233, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } },
         EFFECT_CONTROL_API_VERSION,
-        (EFFECT_FLAG_TYPE_AUXILIARY | EFFECT_FLAG_HW_ACC_TUNNEL),
+        (EFFECT_FLAG_TYPE_AUXILIARY | EFFECT_FLAG_HW_ACC_TUNNEL | EFFECT_FLAG_VOLUME_CTRL),
         0, /* TODO */
         1,
         "MSM offload Auxiliary Environmental Reverb",
@@ -44,7 +44,8 @@
         {0xc2e5d5f0, 0x94bd, 0x4763, 0x9cac, {0x4e, 0x23, 0x4d, 0x06, 0x83, 0x9e}},
         {0xeb64ea04, 0x973b, 0x43d2, 0x8f5e, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
         EFFECT_CONTROL_API_VERSION,
-        (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST | EFFECT_FLAG_HW_ACC_TUNNEL),
+        (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST | EFFECT_FLAG_HW_ACC_TUNNEL |
+                EFFECT_FLAG_VOLUME_CTRL),
         0, /* TODO */
         1,
         "MSM offload Insert Environmental Reverb",
@@ -56,7 +57,7 @@
         {0x47382d60, 0xddd8, 0x11db, 0xbf3a, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
         {0x6987be09, 0xb142, 0x4b41, 0x9056, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
         EFFECT_CONTROL_API_VERSION,
-        (EFFECT_FLAG_TYPE_AUXILIARY | EFFECT_FLAG_HW_ACC_TUNNEL),
+        (EFFECT_FLAG_TYPE_AUXILIARY | EFFECT_FLAG_HW_ACC_TUNNEL | EFFECT_FLAG_VOLUME_CTRL),
         0, /* TODO */
         1,
         "MSM offload Auxiliary Preset Reverb",
@@ -68,7 +69,8 @@
         {0x47382d60, 0xddd8, 0x11db, 0xbf3a, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
         {0xaa2bebf6, 0x47cf, 0x4613, 0x9bca, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
         EFFECT_CONTROL_API_VERSION,
-        (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST | EFFECT_FLAG_HW_ACC_TUNNEL),
+        (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_INSERT_FIRST | EFFECT_FLAG_HW_ACC_TUNNEL |
+                EFFECT_FLAG_VOLUME_CTRL),
         0, /* TODO */
         1,
         "MSM offload Insert Preset Reverb",
diff --git a/post_proc/virtualizer.c b/post_proc/virtualizer.c
index 40bbf38..b9e4fb9 100644
--- a/post_proc/virtualizer.c
+++ b/post_proc/virtualizer.c
@@ -31,7 +31,8 @@
         {0x37cc2c00, 0xdddd, 0x11db, 0x8577, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
         {0x509a4498, 0x561a, 0x4bea, 0xb3b1, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // uuid
         EFFECT_CONTROL_API_VERSION,
-        (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_DEVICE_IND | EFFECT_FLAG_HW_ACC_TUNNEL),
+        (EFFECT_FLAG_TYPE_INSERT | EFFECT_FLAG_DEVICE_IND | EFFECT_FLAG_HW_ACC_TUNNEL |
+                EFFECT_FLAG_VOLUME_CTRL),
         0, /* TODO */
         1,
         "MSM offload virtualizer",
diff --git a/post_proc/volume_listener.c b/post_proc/volume_listener.c
index 1402ae6..5494fd0 100644
--- a/post_proc/volume_listener.c
+++ b/post_proc/volume_listener.c
@@ -26,7 +26,9 @@
 #include <cutils/properties.h>
 #include <platform_api.h>
 
-#define PRIMARY_HAL_PATH XSTR(LIB_AUDIO_HAL)
+#define PRIMARY_HAL_FILENAME XSTR(LIB_AUDIO_HAL)
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
 #define XSTR(x) STR(x)
 #define STR(x) #x
 
@@ -200,6 +202,10 @@
 /* lock must be held when modifying or accessing created_effects_list */
 pthread_mutex_t vol_listner_init_lock;
 
+/* Treblized modules locations */
+static const char *primary_audio_hal_path[] =
+    {"/vendor/lib/hw/", "/system/lib/hw/"};
+
 /*
  *  Local functions
  */
@@ -366,7 +372,9 @@
             ALOGE("%s: EFFECT_CMD_INIT: %s, sending -EINVAL", __func__,
                   (p_reply_data == NULL) ? "p_reply_data is NULL" :
                   "*reply_size != sizeof(int)");
-            return -EINVAL;
+            android_errorWriteLog(0x534e4554, "32669549");
+            status = -EINVAL;
+            goto exit;
         }
         *(int *)p_reply_data = 0;
         break;
@@ -375,7 +383,9 @@
         ALOGV("%s :: cmd called EFFECT_CMD_SET_CONFIG", __func__);
         if (p_cmd_data == NULL || cmd_size != sizeof(effect_config_t)
                 || p_reply_data == NULL || reply_size == NULL || *reply_size != sizeof(int)) {
-            return -EINVAL;
+            android_errorWriteLog(0x534e4554, "32669549");
+            status = -EINVAL;
+            goto exit;
         }
         context->config = *(effect_config_t *)p_cmd_data;
         *(int *)p_reply_data = 0;
@@ -399,7 +409,9 @@
             ALOGE("%s: EFFECT_CMD_OFFLOAD: %s, sending -EINVAL", __func__,
                   (p_reply_data == NULL) ? "p_reply_data is NULL" :
                   "*reply_size != sizeof(int)");
-            return -EINVAL;
+            android_errorWriteLog(0x534e4554, "32669549");
+            status = -EINVAL;
+            goto exit;
         }
         *(int *)p_reply_data = 0;
         break;
@@ -555,9 +567,27 @@
     return 0;
 }
 
+static bool resolve_audio_hal_path(char *file_name, int mode) {
+    char file_path[PATH_MAX];
+    unsigned long i;
+
+    for (i = 0; i < ARRAY_SIZE(primary_audio_hal_path); i++) {
+        snprintf(file_path, PATH_MAX, "%s/%s",
+            primary_audio_hal_path[i], file_name);
+        if (F_OK == access(file_path, mode)) {
+            strcpy(file_name, file_path);
+            return true;
+        }
+    }
+    return false;
+}
+
 static void init_once()
 {
     int max_table_ent = 0;
+    void *hal_lib_pointer = NULL;
+    char primary_hal_path[PATH_MAX] = {0};
+
     if (initialized) {
         ALOGV("%s : already init .. do nothing", __func__);
         return;
@@ -569,52 +599,54 @@
 
     pthread_mutex_init(&vol_listner_init_lock, NULL);
 
+    strcpy(primary_hal_path, PRIMARY_HAL_FILENAME);
     // get hal function pointer
-    if (access(PRIMARY_HAL_PATH, R_OK) == 0) {
-        void *hal_lib_pointer = dlopen(PRIMARY_HAL_PATH, RTLD_NOW);
-        if (hal_lib_pointer == NULL) {
-            ALOGE("%s: DLOPEN failed for %s", __func__, PRIMARY_HAL_PATH);
+    if (resolve_audio_hal_path(primary_hal_path, R_OK)) {
+        hal_lib_pointer = dlopen(primary_hal_path, RTLD_NOW);
+    } else {
+        ALOGE("%s: not able to acces lib: %s", __func__, PRIMARY_HAL_FILENAME);
+    }
+
+    if (!hal_lib_pointer) {
+        ALOGE("%s: DLOPEN failed for %s", __func__, primary_hal_path);
+    } else {
+        ALOGV("%s: DLOPEN of %s Succes .. next get HAL entry function", __func__, primary_hal_path);
+        send_gain_dep_cal = (bool (*)(int))dlsym(hal_lib_pointer, AHAL_GAIN_DEPENDENT_INTERFACE_FUNCTION);
+        if (send_gain_dep_cal == NULL) {
+            ALOGE("Couldnt able to get the function symbol");
+        }
+        get_custom_gain_table = (int (*) (struct amp_db_and_gain_table *, int))dlsym(hal_lib_pointer, AHAL_GAIN_GET_MAPPING_TABLE);
+        if (get_custom_gain_table == NULL) {
+            ALOGE("Couldnt able to get the function AHAL_GAIN_GET_MAPPING_TABLE  symbol");
         } else {
-            ALOGV("%s: DLOPEN of %s Succes .. next get HAL entry function", __func__, PRIMARY_HAL_PATH);
-            send_gain_dep_cal = (bool (*)(int))dlsym(hal_lib_pointer, AHAL_GAIN_DEPENDENT_INTERFACE_FUNCTION);
-            if (send_gain_dep_cal == NULL) {
-                ALOGE("Couldnt able to get the function symbol");
-            }
-            get_custom_gain_table = (int (*) (struct amp_db_and_gain_table *, int))dlsym(hal_lib_pointer, AHAL_GAIN_GET_MAPPING_TABLE);
-            if (get_custom_gain_table == NULL) {
-                ALOGE("Couldnt able to get the function AHAL_GAIN_GET_MAPPING_TABLE  symbol");
-            } else {
-                max_table_ent = get_custom_gain_table(volume_curve_gain_mapping_table, MAX_VOLUME_CAL_STEPS);
-                // if number of entries is 0 use default
-                // if number of entries > MAX_VOLUME_CAL_STEPS (this should never happen) then in this case
-                // use only default number of steps but this will result in unexpected behaviour
+            max_table_ent = get_custom_gain_table(volume_curve_gain_mapping_table, MAX_VOLUME_CAL_STEPS);
+            // if number of entries is 0 use default
+            // if number of entries > MAX_VOLUME_CAL_STEPS (this should never happen) then in this case
+            // use only default number of steps but this will result in unexpected behaviour
 
-                if (max_table_ent > 0 && max_table_ent <= MAX_VOLUME_CAL_STEPS) {
-                    if (max_table_ent < total_volume_cal_step) {
-                        for (int i = max_table_ent; i < total_volume_cal_step; i++ ) {
-                            volume_curve_gain_mapping_table[i].amp = 0;
-                            volume_curve_gain_mapping_table[i].db = 0;
-                            volume_curve_gain_mapping_table[i].level = -1;
-                        }
+            if (max_table_ent > 0 && max_table_ent <= MAX_VOLUME_CAL_STEPS) {
+                if (max_table_ent < total_volume_cal_step) {
+                    for (int i = max_table_ent; i < total_volume_cal_step; i++ ) {
+                        volume_curve_gain_mapping_table[i].amp = 0;
+                        volume_curve_gain_mapping_table[i].db = 0;
+                        volume_curve_gain_mapping_table[i].level = -1;
                     }
-                    total_volume_cal_step = max_table_ent;
-                    ALOGD("%s: using custome volume table", __func__);
-                } else {
-                    ALOGD("%s: using default volume table", __func__);
                 }
+                total_volume_cal_step = max_table_ent;
+                ALOGD("%s: using custome volume table", __func__);
+            } else {
+                ALOGD("%s: using default volume table", __func__);
+            }
 
-                if (dumping_enabled) {
-                    ALOGD("%s: dumping table here .. size of table received %d",
-                           __func__, max_table_ent);
-                    for (int i = 0; i < MAX_VOLUME_CAL_STEPS ; i++)
-                        ALOGD("[%d]  %f %f %d", i, volume_curve_gain_mapping_table[i].amp,
-                                                   volume_curve_gain_mapping_table[i].db,
-                                                   volume_curve_gain_mapping_table[i].level);
-                }
+            if (dumping_enabled) {
+                ALOGD("%s: dumping table here .. size of table received %d",
+                       __func__, max_table_ent);
+                for (int i = 0; i < MAX_VOLUME_CAL_STEPS ; i++)
+                    ALOGD("[%d]  %f %f %d", i, volume_curve_gain_mapping_table[i].amp,
+                                               volume_curve_gain_mapping_table[i].db,
+                                               volume_curve_gain_mapping_table[i].level);
             }
         }
-    } else {
-        ALOGE("%s: not able to acces lib %s ", __func__, PRIMARY_HAL_PATH);
     }
 
     // check system property to see if dumping is required
diff --git a/visualizer/Android.mk b/visualizer/Android.mk
index 87d4987..e318214 100644
--- a/visualizer/Android.mk
+++ b/visualizer/Android.mk
@@ -29,6 +29,8 @@
 
 LOCAL_MODULE_RELATIVE_PATH := soundfx
 LOCAL_MODULE:= libqcomvisualizer
+LOCAL_MODULE_OWNER := qcom
+LOCAL_PROPRIETARY_MODULE := true
 
 LOCAL_C_INCLUDES := \
 	external/tinyalsa/include \
diff --git a/visualizer/offload_visualizer.c b/visualizer/offload_visualizer.c
index c56ebff..4d1373f 100644
--- a/visualizer/offload_visualizer.c
+++ b/visualizer/offload_visualizer.c
@@ -81,11 +81,11 @@
     effect_ops_t ops;
 };
 
-typedef struct output_context_s {
+struct output_context_s {
     struct listnode outputs_list_node;  /* node in active_outputs_list */
     audio_io_handle_t handle; /* io handle */
     struct listnode effects_list; /* list of effects attached to this output */
-} output_context_t;
+};
 
 
 /* maximum time since last capture buffer update before resetting capture buffer. This means
@@ -427,7 +427,7 @@
 
 __attribute__ ((visibility ("default")))
 int visualizer_hal_start_output(audio_io_handle_t output, int pcm_id) {
-    int ret;
+    int ret = 0;
     struct listnode *node;
 
     ALOGV("%s output %d pcm_id %d", __func__, output, pcm_id);
@@ -473,7 +473,7 @@
 
 __attribute__ ((visibility ("default")))
 int visualizer_hal_stop_output(audio_io_handle_t output, int pcm_id) {
-    int ret;
+    int ret = 0;
     struct listnode *node;
     struct listnode *fx_node;
     output_context_t *out_ctxt;
diff --git a/voice_processing/Android.mk b/voice_processing/Android.mk
index 9b86eaf..e8878ee 100644
--- a/voice_processing/Android.mk
+++ b/voice_processing/Android.mk
@@ -5,6 +5,8 @@
 
 LOCAL_MODULE:= libqcomvoiceprocessing
 LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_OWNER := qcom
+LOCAL_PROPRIETARY_MODULE := true
 LOCAL_MODULE_RELATIVE_PATH := soundfx
 
 LOCAL_SRC_FILES:= \
@@ -14,6 +16,7 @@
     $(call include-path-for, audio-effects)
 
 LOCAL_SHARED_LIBRARIES := \
+    liblog \
     libcutils
 
 LOCAL_SHARED_LIBRARIES += libdl
diff --git a/voice_processing/voice_processing.c b/voice_processing/voice_processing.c
index be3d801..d2b4acb 100644
--- a/voice_processing/voice_processing.c
+++ b/voice_processing/voice_processing.c
@@ -30,7 +30,8 @@
 // local definitions
 //------------------------------------------------------------------------------
 
-#define EFFECTS_DESCRIPTOR_LIBRARY_PATH "/system/lib/soundfx/libqcomvoiceprocessingdescriptors.so"
+#define EFFECTS_DESCRIPTOR_LIBRARY_PATH "/vendor/lib/soundfx/libqcomvoiceprocessingdescriptors.so"
+#define EFFECTS_DESCRIPTOR_LIBRARY_PATH2 "/system/lib/soundfx/libqcomvoiceprocessingdescriptors.so"
 
 // types of pre processing modules
 enum effect_id
@@ -426,12 +427,20 @@
     if (init_status <= 0)
         return init_status;
 
-    if (access(EFFECTS_DESCRIPTOR_LIBRARY_PATH, R_OK) == 0) {
-        lib_handle = dlopen(EFFECTS_DESCRIPTOR_LIBRARY_PATH, RTLD_NOW);
+    const char *path = EFFECTS_DESCRIPTOR_LIBRARY_PATH;
+    int result = access(path, R_OK);
+
+    if (result != 0) {
+        path = EFFECTS_DESCRIPTOR_LIBRARY_PATH2;
+        result = access(path, R_OK);
+    }
+
+    if (result == 0) {
+        lib_handle = dlopen(path, RTLD_NOW);
         if (lib_handle == NULL) {
-            ALOGE("%s: DLOPEN failed for %s", __func__, EFFECTS_DESCRIPTOR_LIBRARY_PATH);
+            ALOGE("%s: DLOPEN failed for %s", __func__, path);
         } else {
-            ALOGV("%s: DLOPEN successful for %s", __func__, EFFECTS_DESCRIPTOR_LIBRARY_PATH);
+            ALOGV("%s: DLOPEN successful for %s", __func__, path);
             desc = (const effect_descriptor_t *)dlsym(lib_handle,
                                                         "qcom_product_aec_descriptor");
             if (desc)
@@ -448,6 +457,8 @@
 //            if (desc)
 //                descriptors[AGC_ID] = desc;
         }
+    } else {
+        ALOGE("%s: can't find %s", __func__, path);
     }
 
     uuid_to_id_table[AEC_ID] = FX_IID_AEC;