Fix parameters passed to pcm_open to include PCM_MONOTONIC am: 635e743ad2
am: 6e14144a03

Change-Id: Ida70817f1c07a8988a04efbb4c7c01ecf3eb5d16
diff --git a/hal/Android.mk b/hal/Android.mk
index 2b27e64..2de6c16 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -67,7 +67,8 @@
 	audio_extn/ext_speaker.c \
 	audio_extn/audio_extn.c \
 	audio_extn/utils.c \
-	$(AUDIO_PLATFORM)/platform.c
+	$(AUDIO_PLATFORM)/platform.c \
+        acdb.c
 
 ifdef MULTIPLE_HW_VARIANTS_ENABLED
   LOCAL_CFLAGS += -DHW_VARIANTS_ENABLED
diff --git a/hal/acdb.c b/hal/acdb.c
new file mode 100644
index 0000000..99599b8
--- /dev/null
+++ b/hal/acdb.c
@@ -0,0 +1,178 @@
+/*
+ * 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_acdb"
+//#define LOG_NDEBUG 0
+#define LOG_NDDEBUG 0
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <dlfcn.h>
+#include <cutils/log.h>
+#include <cutils/str_parms.h>
+#include <system/audio.h>
+#include <tinyalsa/asoundlib.h>
+#include "acdb.h"
+#include <platform_api.h>
+
+#define PLATFORM_CONFIG_KEY_SOUNDCARD_NAME "snd_card_name"
+
+int acdb_init(int snd_card_num)
+{
+
+    int result = -1;
+    char *cvd_version = NULL;
+
+    char *snd_card_name = NULL;
+    struct mixer *mixer = NULL;
+    struct acdb_platform_data *my_data = NULL;
+
+    if(snd_card_num < 0) {
+        ALOGE("invalid sound card number");
+        return result;
+    }
+
+    mixer = mixer_open(snd_card_num);
+    if (!mixer) {
+        ALOGE("%s: Unable to open the mixer card: %d", __func__,
+               snd_card_num);
+        goto cleanup;
+    }
+
+    my_data = calloc(1, sizeof(struct acdb_platform_data));
+    if (!my_data) {
+        ALOGE("failed to allocate acdb platform data");
+        goto cleanup;
+    }
+
+    list_init(&my_data->acdb_meta_key_list);
+
+    my_data->acdb_handle = dlopen(LIB_ACDB_LOADER, RTLD_NOW);
+    if (my_data->acdb_handle == NULL) {
+        ALOGE("%s: DLOPEN failed for %s", __func__, LIB_ACDB_LOADER);
+        goto cleanup;
+    }
+
+    ALOGV("%s: DLOPEN successful for %s", __func__, LIB_ACDB_LOADER);
+
+    my_data->acdb_init_v3 = (acdb_init_v3_t)dlsym(my_data->acdb_handle,
+                                                     "acdb_loader_init_v3");
+    if (my_data->acdb_init_v3 == NULL)
+        ALOGE("%s: dlsym error %s for acdb_loader_init_v3", __func__, dlerror());
+
+    my_data->acdb_init_v2 = (acdb_init_v2_cvd_t)dlsym(my_data->acdb_handle,
+                                                     "acdb_loader_init_v2");
+    if (my_data->acdb_init_v2 == NULL)
+        ALOGE("%s: dlsym error %s for acdb_loader_init_v2", __func__, dlerror());
+
+    my_data->acdb_init = (acdb_init_t)dlsym(my_data->acdb_handle,
+                                                 "acdb_loader_init_ACDB");
+    if (my_data->acdb_init == NULL && my_data->acdb_init_v2 == NULL
+        && my_data->acdb_init_v3 == NULL) {
+        ALOGE("%s: dlsym error %s for acdb_loader_init_ACDB", __func__, dlerror());
+        goto cleanup;
+    }
+
+    /* Get CVD version */
+    cvd_version = calloc(1, MAX_CVD_VERSION_STRING_SIZE);
+    if (!cvd_version) {
+        ALOGE("%s: Failed to allocate cvd version", __func__);
+        goto cleanup;
+    } else {
+        struct mixer_ctl *ctl = NULL;
+        int count = 0;
+
+        ctl = mixer_get_ctl_by_name(mixer, CVD_VERSION_MIXER_CTL);
+        if (!ctl) {
+            ALOGE("%s: Could not get ctl for mixer cmd - %s",  __func__, CVD_VERSION_MIXER_CTL);
+            goto cleanup;
+        }
+        mixer_ctl_update(ctl);
+
+        count = mixer_ctl_get_num_values(ctl);
+        if (count > MAX_CVD_VERSION_STRING_SIZE)
+            count = MAX_CVD_VERSION_STRING_SIZE;
+
+        result = mixer_ctl_get_array(ctl, cvd_version, count);
+        if (result != 0) {
+            ALOGE("%s: ERROR! mixer_ctl_get_array() failed to get CVD Version", __func__);
+            goto cleanup;
+        }
+    }
+
+    /* Get Sound card name */
+    snd_card_name = strdup(mixer_get_name(mixer));
+    if (!snd_card_name) {
+        ALOGE("failed to allocate memory for snd_card_name");
+        result = -1;
+        goto cleanup;
+    }
+
+    if (my_data->acdb_init_v3)
+        result = my_data->acdb_init_v3(snd_card_name, cvd_version,
+                                       &my_data->acdb_meta_key_list);
+    else if (my_data->acdb_init_v2)
+        result = my_data->acdb_init_v2(snd_card_name, cvd_version, 0);
+    else
+        result = my_data->acdb_init();
+
+cleanup:
+    if (NULL != my_data) {
+        if (my_data->acdb_handle)
+            dlclose(my_data->acdb_handle);
+
+        struct listnode *node;
+        struct meta_key_list *key_info;
+        list_for_each(node, &my_data->acdb_meta_key_list) {
+            key_info = node_to_item(node, struct meta_key_list, list);
+            free(key_info);
+        }
+        free(my_data);
+    }
+
+    mixer_close(mixer);
+    free(cvd_version);
+    free(snd_card_name);
+
+    return result;
+}
+
+int acdb_set_parameters(void *platform, struct str_parms *parms)
+{
+    struct acdb_platform_data *my_data = (struct acdb_platform_data *)platform;
+    char value[128];
+    char *kv_pairs = str_parms_to_str(parms);
+    int ret = 0;
+
+    if (kv_pairs == NULL) {
+        ret = -EINVAL;
+        ALOGE("%s: key-value pair is NULL",__func__);
+        goto done;
+    }
+
+    ret = str_parms_get_str(parms, PLATFORM_CONFIG_KEY_SOUNDCARD_NAME,
+                            value, sizeof(value));
+    if (ret >= 0) {
+        str_parms_del(parms, PLATFORM_CONFIG_KEY_SOUNDCARD_NAME);
+        my_data->snd_card_name = strdup(value);
+        ALOGV("%s: sound card name %s", __func__, my_data->snd_card_name);
+    }
+
+done:
+    free(kv_pairs);
+
+    return ret;
+}
diff --git a/hal/acdb.h b/hal/acdb.h
new file mode 100644
index 0000000..08026fb
--- /dev/null
+++ b/hal/acdb.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ACDB_H
+#define ACDB_H
+
+#include <cutils/list.h>
+#include <linux/msm_audio_calibration.h>
+
+#define MAX_CVD_VERSION_STRING_SIZE 100
+#define LIB_ACDB_LOADER "libacdbloader.so"
+#define CVD_VERSION_MIXER_CTL "CVD Version"
+#define ACDB_METAINFO_KEY_MODULE_NAME_LEN 100
+
+/* Audio calibration related functions */
+typedef void (*acdb_deallocate_t)();
+typedef int  (*acdb_init_v3_t)(const char *, char *, struct listnode *);
+typedef int  (*acdb_init_v2_cvd_t)(char *, char *, int);
+typedef int  (*acdb_init_v2_t)(char *);
+typedef int  (*acdb_init_t)();
+typedef void (*acdb_send_audio_cal_t)(int, int);
+typedef void (*acdb_send_voice_cal_t)(int, int);
+typedef int (*acdb_reload_vocvoltable_t)(int);
+typedef int (*acdb_send_gain_dep_cal_t)(int, int, int, int, int);
+typedef int (*acdb_send_custom_top_t) (void);
+
+struct meta_key_list {
+    struct listnode list;
+    struct audio_cal_info_metainfo cal_info;
+    char name[ACDB_METAINFO_KEY_MODULE_NAME_LEN];
+};
+
+struct acdb_platform_data {
+    /* Audio calibration related functions */
+    void                       *acdb_handle;
+    acdb_init_t                acdb_init;
+    acdb_init_v2_cvd_t         acdb_init_v2;
+    acdb_init_v3_t             acdb_init_v3;
+    char *snd_card_name;
+    struct listnode acdb_meta_key_list;
+};
+
+int acdb_init(int);
+
+int acdb_set_metainfo_key(void *platform, char *name, int key);
+int acdb_set_parameters(void *platform, struct str_parms *parms);
+#endif //ACDB_H
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index b734cb6..600c179 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -79,6 +79,9 @@
 #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)
+#define audio_extn_usb_get_max_channels(dir)                           (0)
+#define audio_extn_usb_get_max_bit_width(dir)                          (0)
+#define audio_extn_usb_sup_sample_rates(t, s, l)                       (0)
 #else
 void audio_extn_usb_init(void *adev);
 void audio_extn_usb_deinit();
@@ -92,6 +95,9 @@
 int audio_extn_usb_set_sidetone_gain(struct str_parms *parms,
                                      char *value, int len);
 bool audio_extn_usb_is_capture_supported();
+int audio_extn_usb_get_max_channels(bool is_playback);
+int audio_extn_usb_get_max_bit_width(bool is_playback);
+int audio_extn_usb_sup_sample_rates(bool is_playback, uint32_t *sr, uint32_t l);
 #endif
 
 
@@ -137,6 +143,8 @@
 void audio_extn_utils_send_default_app_type_cfg(void *platform, struct mixer *mixer);
 int audio_extn_utils_send_app_type_cfg(struct audio_device *adev,
                                        struct audio_usecase *usecase);
+void audio_extn_utils_send_audio_calibration(struct audio_device *adev,
+                                             struct audio_usecase *usecase);
 #ifndef HWDEP_CAL_ENABLED
 #define  audio_extn_hwdep_cal_send(snd_card, acdb_handle) (0)
 #else
@@ -178,4 +186,8 @@
 int audio_extn_snd_mon_unregister_listener(void *stream);
 #endif
 
+bool audio_extn_utils_resolve_config_file(char[]);
+int audio_extn_utils_get_platform_info(const char* snd_card_name,
+                                       char* platform_info_file);
+int audio_extn_utils_get_snd_card_num();
 #endif /* AUDIO_EXTN_H */
diff --git a/hal/audio_extn/sndmonitor.c b/hal/audio_extn/sndmonitor.c
index 58ab43d..3c91dda 100644
--- a/hal/audio_extn/sndmonitor.c
+++ b/hal/audio_extn/sndmonitor.c
@@ -152,7 +152,7 @@
     size_t len = 0;
     ssize_t bytes_read;
     char path[128] = {0};
-    char *ptr, *saveptr;
+    char *ptr, *saveptr, *card_id;
     int line_no=0;
     unsigned int num_cards=0, num_cpe=0;
     FILE *fp;
@@ -180,6 +180,19 @@
         if (!ptr)
             continue;
 
+        card_id = strtok_r(saveptr+1, "]", &saveptr);
+        if (!card_id)
+            continue;
+
+        // Limit to sound cards associated with ADSP
+        if ((strncasecmp(card_id, "msm", 3) != 0) &&
+            (strncasecmp(card_id, "sdm", 3) != 0) &&
+            (strncasecmp(card_id, "sdc", 3) != 0) &&
+            (strncasecmp(card_id, "apq", 3) != 0)) {
+            ALOGW("Skip over non-ADSP snd card %s", card_id);
+            continue;
+        }
+
         snprintf(path, sizeof(path), "/proc/asound/card%s/state", ptr);
         ALOGV("Opening sound card state : %s", path);
 
diff --git a/hal/audio_extn/usb.c b/hal/audio_extn/usb.c
index 3747318..4e4c70d 100644
--- a/hal/audio_extn/usb.c
+++ b/hal/audio_extn/usb.c
@@ -42,9 +42,12 @@
 #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};
+    {192000, 176400, 96000, 88200, 64000, 48000, 44100};
+static uint32_t supported_sample_rates_mask[2];
+static const uint32_t MAX_SAMPLE_RATE_SIZE =
+        (sizeof(supported_sample_rates)/sizeof(supported_sample_rates[0]));
 
-#define  MAX_SAMPLE_RATE_SIZE  sizeof(supported_sample_rates)/sizeof(supported_sample_rates[0])
+// assert on sizeof bm v/s size of rates if needed
 
 enum usb_usecase_type{
     USB_PLAYBACK = 0,
@@ -211,7 +214,7 @@
     return 0;
 }
 
-static int usb_get_sample_rates(char *rates_str,
+static int usb_get_sample_rates(int type, char *rates_str,
                                 struct usb_device_config *config)
 {
     uint32_t i;
@@ -242,6 +245,7 @@
             if (supported_sample_rates[i] >= min_sr &&
                 supported_sample_rates[i] <= max_sr) {
                 config->rates[sr_size++] = supported_sample_rates[i];
+                supported_sample_rates_mask[type] |= (1<<i);
                 ALOGI_IF(usb_audio_debug_enable,
                     "%s: continuous sample rate supported_sample_rates[%d] %d",
                     __func__, i, supported_sample_rates[i]);
@@ -256,6 +260,7 @@
                         "%s: sr %d, supported_sample_rates[%d] %d -> matches!!",
                         __func__, sr, i, supported_sample_rates[i]);
                     config->rates[sr_size++] = supported_sample_rates[i];
+                    supported_sample_rates_mask[type] |= (1<<i);
                 }
             }
             next_sr_string = strtok_r(NULL, " ,.-", &temp_ptr);
@@ -285,6 +290,7 @@
     char *bit_width_str = NULL;
     struct usb_device_config * usb_device_info;
     bool check = false;
+    int tries=5;
 
     memset(path, 0, sizeof(path));
     ALOGV("%s: for %s", __func__, (type == USB_PLAYBACK) ?
@@ -293,12 +299,20 @@
     /* TODO: convert the below to using alsa_utils */
     ret = snprintf(path, sizeof(path), "/proc/asound/card%u/stream0",
              card);
-    if(ret < 0) {
+    if (ret < 0) {
         ALOGE("%s: failed on snprintf (%d) to path %s\n",
           __func__, ret, path);
         goto done;
     }
 
+    while (tries--) {
+        if (access(path, F_OK) < 0) {
+            ALOGW("stream %s doesn't exist retrying\n", path);
+            sleep(1);
+            continue;
+        }
+    }
+
     fd = open(path, O_RDONLY);
     if (fd <0) {
         ALOGE("%s: error failed to open config file %s error: %d\n",
@@ -418,7 +432,7 @@
         }
         memcpy(rates_str, rates_str_start, size);
         rates_str[size] = '\0';
-        ret = usb_get_sample_rates(rates_str, usb_device_info);
+        ret = usb_get_sample_rates(type, rates_str, usb_device_info);
         if (rates_str)
             free(rates_str);
         if (ret < 0) {
@@ -513,18 +527,26 @@
     return;
 }
 
+static inline bool usb_output_device(audio_devices_t device) {
+    // ignore accessory for now
+    if (device == AUDIO_DEVICE_OUT_USB_ACCESSORY) {
+        return false;
+    }
+    return audio_is_usb_out_device(device);
+}
+
+static inline bool usb_input_device(audio_devices_t device) {
+    // ignore accessory for now
+    if (device == AUDIO_DEVICE_IN_USB_ACCESSORY) {
+        return false;
+    }
+    return audio_is_usb_in_device(device);
+}
+
 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;
+    return usb_output_device(device) ||
+           usb_input_device(device);
 }
 
 static void usb_print_active_device(void){
@@ -816,7 +838,7 @@
         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 (usb_output_device(card_info->usb_device_type)) {
             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,
@@ -861,8 +883,8 @@
                  "%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)){
+        if ((is_playback && usb_output_device(card_info->usb_device_type)) ||
+            (!is_playback && usb_input_device(card_info->usb_device_type))) {
             usb_audio_backend_apply_policy(&card_info->usb_device_conf_list,
                                            bit_width,
                                            sample_rate,
@@ -876,6 +898,77 @@
     return true;
 }
 
+#define _MAX(x, y) (((x) >= (y)) ? (x) : (y))
+#define _MIN(x, y) (((x) <= (y)) ? (x) : (y))
+
+int audio_extn_usb_get_max_channels(bool is_playback)
+{
+    struct listnode *node_i, *node_j;
+    struct usb_device_config *dev_info;
+    struct usb_card_config *card_info;
+    unsigned int max_ch = 1;
+    list_for_each(node_i, &usbmod->usb_card_conf_list) {
+            card_info = node_to_item(node_i, struct usb_card_config, list);
+            if (usb_output_device(card_info->usb_device_type) && !is_playback)
+                continue;
+            else if (usb_input_device(card_info->usb_device_type) && is_playback)
+                continue;
+
+            list_for_each(node_j, &card_info->usb_device_conf_list) {
+                dev_info = node_to_item(node_j, struct usb_device_config, list);
+                max_ch = _MAX(max_ch, dev_info->channel_count);
+            }
+    }
+
+    return max_ch;
+}
+
+int audio_extn_usb_get_max_bit_width(bool is_playback)
+{
+    struct listnode *node_i, *node_j;
+    struct usb_device_config *dev_info;
+    struct usb_card_config *card_info;
+    unsigned int max_bw = 16;
+    list_for_each(node_i, &usbmod->usb_card_conf_list) {
+            card_info = node_to_item(node_i, struct usb_card_config, list);
+            if (usb_output_device(card_info->usb_device_type) && !is_playback)
+                continue;
+            else if (usb_input_device(card_info->usb_device_type) && is_playback)
+                continue;
+
+            list_for_each(node_j, &card_info->usb_device_conf_list) {
+                dev_info = node_to_item(node_j, struct usb_device_config, list);
+                max_bw = _MAX(max_bw, dev_info->bit_width);
+            }
+    }
+
+    return max_bw;
+}
+
+int audio_extn_usb_sup_sample_rates(bool is_playback,
+                                    uint32_t *sample_rates,
+                                    uint32_t sample_rate_size)
+{
+    struct listnode *node_i, *node_j;
+    struct usb_device_config *dev_info;
+    struct usb_card_config *card_info;
+
+    int type = is_playback ? USB_PLAYBACK : USB_CAPTURE;
+
+    ALOGV("%s supported_sample_rates_mask 0x%x", __func__, supported_sample_rates_mask[type]);
+    uint32_t bm = supported_sample_rates_mask[type];
+    uint32_t tries = _MIN(sample_rate_size, (uint32_t)__builtin_popcount(bm));
+
+    int i = 0;
+    while (tries--) {
+        int idx = __builtin_ffs(bm) - 1;
+        sample_rates[i++] = supported_sample_rates[idx];
+        bm &= ~(1<<idx);
+    }
+
+    return i;
+}
+
 bool audio_extn_usb_is_capture_supported()
 {
     if (usbmod == NULL) {
@@ -930,22 +1023,24 @@
         goto exit;
     }
     list_init(&usb_card_info->usb_device_conf_list);
-    if (device & AUDIO_DEVICE_OUT_USB_DEVICE) {
+    if (usb_output_device(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_card_info->usb_device_type = 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) {
+    } else if (usb_input_device(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;
+            usb_card_info->usb_device_type = device;
             usbmod->is_capture_supported = true;
             list_add_tail(&usbmod->usb_card_conf_list, &usb_card_info->list);
             goto exit;
         }
+    } else {
+        ALOGW("%s: unknown device 0x%x", __func__, device);
     }
     /* free memory in error case */
     if (usb_card_info != NULL)
@@ -993,10 +1088,15 @@
                 free(node_to_item(node_j, struct usb_device_config, list));
             }
             list_remove(node_i);
+            if (card_info->usb_snd_mixer) {
+                mixer_close(card_info->usb_snd_mixer);
+            }
             free(node_to_item(node_i, struct usb_card_config, list));
         }
     }
     usbmod->is_capture_supported = false;
+    supported_sample_rates_mask[USB_PLAYBACK] = 0;
+    supported_sample_rates_mask[USB_CAPTURE] = 0;
 exit:
     if (usb_audio_debug_enable)
         usb_print_active_device();
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index d2bb42c..eb0f9f6 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -26,6 +26,7 @@
 #include <cutils/log.h>
 #include <cutils/misc.h>
 
+#include "acdb.h"
 #include "audio_hw.h"
 #include "platform.h"
 #include "platform_api.h"
@@ -91,7 +92,7 @@
     return;
 }
 
-int audio_extn_utils_send_app_type_cfg(struct audio_device *adev,
+static int audio_extn_utils_send_app_type_cfg_hfp(struct audio_device *adev,
                                        struct audio_usecase *usecase)
 {
     struct mixer_ctl *ctl;
@@ -177,3 +178,276 @@
 exit_send_app_type_cfg:
     return rc;
 }
+
+int audio_extn_utils_send_app_type_cfg(struct audio_device *adev,
+                                       struct audio_usecase *usecase)
+{
+    int len = 0;
+    if (usecase->type == PCM_HFP_CALL) {
+        return audio_extn_utils_send_app_type_cfg_hfp(adev, usecase);
+    }
+
+    if (usecase->type != PCM_PLAYBACK || !platform_supports_app_type_cfg())
+        return -1;
+
+    size_t app_type_cfg[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
+    int pcm_device_id = platform_get_pcm_device_id(usecase->id, PCM_PLAYBACK);
+
+    char mixer_ctl_name[MAX_LENGTH_MIXER_CONTROL_IN_INT] = {0};
+    snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
+             "Audio Stream %d App Type Cfg", pcm_device_id);
+    struct mixer_ctl *ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s", __func__,
+              mixer_ctl_name);
+        return -EINVAL;
+    }
+
+    snd_device_t snd_device = usecase->out_snd_device; // add speaker prot changes if needed
+    int acdb_dev_id = platform_get_snd_device_acdb_id(snd_device);
+    if (acdb_dev_id <= 0) {
+        ALOGE("%s: Couldn't get the acdb dev id", __func__);
+        return -1;
+    }
+
+    if (usecase->stream.out->devices & AUDIO_DEVICE_OUT_SPEAKER) {
+        usecase->stream.out->app_type_cfg.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
+    } else if (snd_device == SND_DEVICE_OUT_USB_HEADSET ||
+               snd_device == SND_DEVICE_OUT_USB_HEADPHONES) {
+        platform_check_and_update_copp_sample_rate(adev->platform, snd_device,
+                                                   usecase->stream.out->sample_rate,
+                                                   &usecase->stream.out->app_type_cfg.sample_rate);
+    }
+
+    int32_t sample_rate = usecase->stream.out->app_type_cfg.sample_rate;
+    int app_type;
+    if (!audio_is_linear_pcm(usecase->stream.out->format)) {
+        platform_get_default_app_type_v2(adev->platform,
+                                         PCM_PLAYBACK,
+                                         &app_type);
+    } else if (usecase->stream.out->format == AUDIO_FORMAT_PCM_16_BIT) {
+        platform_get_app_type_v2(adev->platform,
+                                 16,
+                                 sample_rate,
+                                 PCM_PLAYBACK,
+                                 &app_type);
+    } else if (usecase->stream.out->format == AUDIO_FORMAT_PCM_24_BIT_PACKED ||
+               usecase->stream.out->format == AUDIO_FORMAT_PCM_8_24_BIT) {
+        platform_get_app_type_v2(adev->platform,
+                                 24,
+                                 sample_rate,
+                                 PCM_PLAYBACK,
+                                 &app_type);
+    } else if (usecase->stream.out->format == AUDIO_FORMAT_PCM_32_BIT) {
+        platform_get_app_type_v2(adev->platform,
+                                 32,
+                                 sample_rate,
+                                 PCM_PLAYBACK,
+                                 &app_type);
+    } else {
+        ALOGE("%s bad format\n", __func__);
+        return -1;
+    }
+
+    //XXX this would be set somewhere else
+    usecase->stream.out->app_type_cfg.app_type = app_type;
+    app_type_cfg[len++] = app_type;
+    app_type_cfg[len++] = acdb_dev_id;
+    app_type_cfg[len++] = sample_rate;
+
+    // add be_idx once available
+    // if (snd_device_be_idx > 0)
+    //    app_type_cfg[len++] = snd_device_be_idx;
+
+    ALOGI("%s PLAYBACK app_type %d, acdb_dev_id %d, sample_rate %d",
+          __func__, app_type, acdb_dev_id, sample_rate);
+
+    mixer_ctl_set_array(ctl, app_type_cfg, len);
+    return 0;
+}
+
+void audio_extn_utils_send_audio_calibration(struct audio_device *adev,
+                                             struct audio_usecase *usecase)
+{
+    int type = usecase->type;
+    int app_type = 0;
+
+    if (type == PCM_PLAYBACK && usecase->stream.out != NULL) {
+        struct stream_out *out = usecase->stream.out;
+        ALOGV("%s send cal for app_type %d, rate %d", __func__, out->app_type_cfg.app_type,
+              usecase->stream.out->app_type_cfg.sample_rate);
+        platform_send_audio_calibration_v2(adev->platform, usecase,
+                                        out->app_type_cfg.app_type,
+                                        usecase->stream.out->app_type_cfg.sample_rate);
+    } else if (type == PCM_CAPTURE && usecase->stream.in != NULL) {
+        // TBD
+        // platform_send_audio_calibration_v2(adev->platform, usecase,
+        // usecase->stream.in->app_type_cfg.app_type,
+        // usecase->stream.in->app_type_cfg.sample_rate);
+        // uncomment these once send_app_type_cfg and the config entries for
+        // non-16 bit capture are figured out.
+        platform_get_default_app_type_v2(adev->platform, type, &app_type);
+        platform_send_audio_calibration_v2(adev->platform, usecase, app_type, 48000);
+    } else {
+        /* when app type is default. the sample rate is not used to send cal */
+        platform_get_default_app_type_v2(adev->platform, type, &app_type);
+        platform_send_audio_calibration_v2(adev->platform, usecase, app_type, 48000);
+    }
+}
+
+#define MAX_SND_CARD 8
+#define RETRY_US 500000
+#define RETRY_NUMBER 10
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+static const char *kConfigLocationList[] =
+        {"/odm/etc", "/vendor/etc", "/system/etc"};
+static const int kConfigLocationListSize =
+        (sizeof(kConfigLocationList) / sizeof(kConfigLocationList[0]));
+
+bool audio_extn_utils_resolve_config_file(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;
+}
+
+/* platform_info_file should be size 'MIXER_PATH_MAX_LENGTH' */
+int audio_extn_utils_get_platform_info(const char* snd_card_name, char* platform_info_file)
+{
+    if (NULL == snd_card_name) {
+        return -1;
+    }
+
+    struct snd_card_split *snd_split_handle = NULL;
+    int ret = 0;
+    audio_extn_set_snd_card_split(snd_card_name);
+    snd_split_handle = audio_extn_get_snd_card_split();
+
+    snprintf(platform_info_file, MIXER_PATH_MAX_LENGTH, "%s_%s_%s.xml",
+                     PLATFORM_INFO_XML_BASE_STRING, snd_split_handle->snd_card,
+                     snd_split_handle->form_factor);
+
+    if (!audio_extn_utils_resolve_config_file(platform_info_file)) {
+        memset(platform_info_file, 0, MIXER_PATH_MAX_LENGTH);
+        snprintf(platform_info_file, MIXER_PATH_MAX_LENGTH, "%s_%s.xml",
+                     PLATFORM_INFO_XML_BASE_STRING, snd_split_handle->snd_card);
+
+        if (!audio_extn_utils_resolve_config_file(platform_info_file)) {
+            memset(platform_info_file, 0, MIXER_PATH_MAX_LENGTH);
+            strlcpy(platform_info_file, PLATFORM_INFO_XML_PATH, MIXER_PATH_MAX_LENGTH);
+            ret = audio_extn_utils_resolve_config_file(platform_info_file) ? 0 : -1;
+        }
+    }
+
+    return ret;
+}
+
+int audio_extn_utils_get_snd_card_num()
+{
+
+    void *hw_info = NULL;
+    struct mixer *mixer = NULL;
+    int retry_num = 0;
+    int snd_card_num = 0;
+    const char* snd_card_name = NULL;
+    char platform_info_file[MIXER_PATH_MAX_LENGTH]= {0};
+
+    struct acdb_platform_data *my_data = calloc(1, sizeof(struct acdb_platform_data));
+
+    bool card_verifed[MAX_SND_CARD] = {0};
+    const int retry_limit = property_get_int32("audio.snd_card.open.retries", RETRY_NUMBER);
+
+    for (;;) {
+        if (snd_card_num >= MAX_SND_CARD) {
+            if (retry_num++ >= retry_limit) {
+                ALOGE("%s: Unable to find correct sound card, aborting.", __func__);
+                snd_card_num = -1;
+                goto done;
+            }
+
+            snd_card_num = 0;
+            usleep(RETRY_US);
+            continue;
+        }
+
+        if (card_verifed[snd_card_num]) {
+            ++snd_card_num;
+            continue;
+        }
+
+        mixer = mixer_open(snd_card_num);
+
+        if (!mixer) {
+            ALOGE("%s: Unable to open the mixer card: %d", __func__,
+               snd_card_num);
+            ++snd_card_num;
+            continue;
+        }
+
+        card_verifed[snd_card_num] = true;
+
+        snd_card_name = mixer_get_name(mixer);
+        hw_info = hw_info_init(snd_card_name);
+
+        if (audio_extn_utils_get_platform_info(snd_card_name, platform_info_file) < 0) {
+            ALOGE("Failed to find platform_info_file");
+            goto cleanup;
+        }
+
+        /* Initialize snd card name specific ids and/or backends*/
+        if (snd_card_info_init(platform_info_file, my_data,
+                               &acdb_set_parameters) < 0) {
+            ALOGE("Failed to find platform_info_file");
+            goto cleanup;
+        }
+
+        /* validate the sound card name
+         * my_data->snd_card_name can contain
+         *     <a> complete sound card name, i.e. <device>-<codec>-<form_factor>-snd-card
+         *         example: msm8994-tomtom-mtp-snd-card
+         *     <b> or sub string of the card name, i.e. <device>-<codec>
+         *         example: msm8994-tomtom
+         * snd_card_name is truncated to 32 charaters as per mixer_get_name() implementation
+         * so use min of my_data->snd_card_name and snd_card_name length for comparison
+         */
+
+        if (my_data->snd_card_name != NULL &&
+                strncmp(snd_card_name, my_data->snd_card_name,
+                        min(strlen(snd_card_name), strlen(my_data->snd_card_name))) != 0) {
+            ALOGI("%s: found valid sound card %s, but not primary sound card %s",
+                   __func__, snd_card_name, my_data->snd_card_name);
+            goto cleanup;
+        }
+
+        ALOGI("%s: found sound card %s, primary sound card expected is %s",
+              __func__, snd_card_name, my_data->snd_card_name);
+        break;
+  cleanup:
+        ++snd_card_num;
+        mixer_close(mixer);
+        mixer = NULL;
+        hw_info_deinit(hw_info);
+        hw_info = NULL;
+    }
+
+done:
+    mixer_close(mixer);
+    hw_info_deinit(hw_info);
+
+    if (my_data)
+        free(my_data);
+
+    return snd_card_num;
+}
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 6f0c9c9..e689b28 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -159,6 +159,17 @@
     .avail_min = MMAP_PERIOD_SIZE, //1 ms
 };
 
+struct pcm_config pcm_config_hifi = {
+    .channels = DEFAULT_CHANNEL_COUNT, /* changed when the stream is opened */
+    .rate = DEFAULT_OUTPUT_SAMPLING_RATE, /* changed when the stream is opened */
+    .period_size = DEEP_BUFFER_OUTPUT_PERIOD_SIZE, /* change #define */
+    .period_count = DEEP_BUFFER_OUTPUT_PERIOD_COUNT,
+    .format = PCM_FORMAT_S24_3LE,
+    .start_threshold = 0,
+    .stop_threshold = INT_MAX,
+    .avail_min = 0,
+};
+
 struct pcm_config pcm_config_audio_capture = {
     .channels = DEFAULT_CHANNEL_COUNT,
     .period_count = AUDIO_CAPTURE_PERIOD_COUNT,
@@ -227,7 +238,7 @@
 const char * const use_case_table[AUDIO_USECASE_MAX] = {
     [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = "deep-buffer-playback",
     [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = "low-latency-playback",
-    [USECASE_AUDIO_PLAYBACK_MULTI_CH] = "multi-channel-playback",
+    [USECASE_AUDIO_PLAYBACK_HIFI] = "hifi-playback",
     [USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback",
     [USECASE_AUDIO_PLAYBACK_TTS] = "audio-tts-playback",
     [USECASE_AUDIO_PLAYBACK_ULL] = "audio-ull-playback",
@@ -236,6 +247,7 @@
     [USECASE_AUDIO_RECORD] = "audio-record",
     [USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record",
     [USECASE_AUDIO_RECORD_MMAP] = "mmap-record",
+    [USECASE_AUDIO_RECORD_HIFI] = "hifi-record",
 
     [USECASE_AUDIO_HFP_SCO] = "hfp-sco",
     [USECASE_AUDIO_HFP_SCO_WB] = "hfp-sco-wb",
@@ -253,6 +265,11 @@
 
     [USECASE_AUDIO_PLAYBACK_AFE_PROXY] = "afe-proxy-playback",
     [USECASE_AUDIO_RECORD_AFE_PROXY] = "afe-proxy-record",
+
+    [USECASE_INCALL_REC_UPLINK] = "incall-rec-uplink",
+    [USECASE_INCALL_REC_DOWNLINK] = "incall-rec-downlink",
+    [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = "incall-rec-uplink-and-downlink",
+
 };
 
 
@@ -263,10 +280,12 @@
     uint32_t value;
 };
 
-static const struct string_to_enum out_channels_name_to_enum_table[] = {
+static const struct string_to_enum channels_name_to_enum_table[] = {
     STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO),
     STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1),
     STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
+    STRING_TO_ENUM(AUDIO_CHANNEL_IN_STEREO),
+    //TBD - string values for channel_in > 2?
 };
 
 static int set_voice_volume_l(struct audio_device *adev, float volume);
@@ -523,6 +542,7 @@
         snd_device = usecase->out_snd_device;
 
     audio_extn_utils_send_app_type_cfg(adev, usecase);
+    audio_extn_utils_send_audio_calibration(adev, usecase);
     strcpy(mixer_path, use_case_table[usecase->id]);
     platform_add_backend_name(adev->platform, mixer_path, snd_device);
     ALOGD("%s: usecase(%d) apply and update mixer path: %s", __func__,  usecase->id, mixer_path);
@@ -784,7 +804,9 @@
     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);
+    bool force_routing =  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
@@ -803,11 +825,13 @@
 
     list_for_each(node, &adev->usecase_list) {
         usecase = node_to_item(node, struct audio_usecase, list);
-        if (usecase->type != PCM_CAPTURE &&
-                usecase != uc_info &&
-                usecase->out_snd_device != snd_device &&
-                usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND &&
-                platform_check_backends_match(snd_device, usecase->out_snd_device)) {
+        if (usecase->type == PCM_CAPTURE || usecase == uc_info)
+            continue;
+
+        if (force_routing ||
+            (usecase->out_snd_device != snd_device &&
+             usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND &&
+             platform_check_backends_match(snd_device, usecase->out_snd_device))) {
             ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..",
                   __func__, use_case_table[usecase->id],
                   platform_get_snd_device_name(usecase->out_snd_device));
@@ -943,6 +967,97 @@
     return ret;
 }
 
+static ssize_t read_usb_sup_sample_rates(bool is_playback __unused,
+                                         uint32_t *supported_sample_rates __unused,
+                                         uint32_t max_rates __unused)
+{
+    ssize_t count = audio_extn_usb_sup_sample_rates(is_playback,
+                                                    supported_sample_rates,
+                                                    max_rates);
+#if !LOG_NDEBUG
+    for (ssize_t i=0; i<count; i++) {
+        ALOGV("%s %s %d", __func__, is_playback ? "P" : "C",
+              supported_sample_rates[i]);
+    }
+#endif
+    return count;
+}
+
+static int read_usb_sup_channel_masks(bool is_playback,
+                                      audio_channel_mask_t *supported_channel_masks,
+                                      uint32_t max_masks __unused)
+{
+    int channels = audio_extn_usb_get_max_channels(is_playback);
+    if (is_playback) {
+        supported_channel_masks[0] =
+                channels < 3 ? audio_channel_out_mask_from_count(channels) :
+                               audio_channel_mask_for_index_assignment_from_count(channels);
+    } else {
+        supported_channel_masks[0] = audio_channel_in_mask_from_count(channels);
+    }
+    ALOGV("%s: %s supported ch %d", __func__,
+          is_playback ? "P" : "C", channels);
+    return 1;
+}
+
+static int read_usb_sup_formats(bool is_playback __unused,
+                                audio_format_t *supported_formats,
+                                uint32_t max_formats __unused)
+{
+    int bitwidth = audio_extn_usb_get_max_bit_width(is_playback);
+    switch (bitwidth) {
+        case 24:
+            // XXX : usb.c returns 24 for s24 and s24_le?
+            supported_formats[0] = AUDIO_FORMAT_PCM_24_BIT_PACKED;
+            break;
+        case 32:
+            supported_formats[0] = AUDIO_FORMAT_PCM_32_BIT;
+            break;
+        case 16:
+        default :
+            supported_formats[0] = AUDIO_FORMAT_PCM_16_BIT;
+            break;
+    }
+    ALOGV("%s: %s supported format %d", __func__,
+          is_playback ? "P" : "C", bitwidth);
+    return 1;
+}
+
+static int read_usb_sup_params_and_compare(bool is_playback,
+                                           audio_format_t *format,
+                                           audio_format_t *supported_formats,
+                                           uint32_t max_formats,
+                                           audio_channel_mask_t *mask,
+                                           audio_channel_mask_t *supported_channel_masks,
+                                           uint32_t max_masks,
+                                           uint32_t *rate,
+                                           uint32_t *supported_sample_rates,
+                                           uint32_t max_rates) {
+    int ret = 0;
+    int num_formats;
+    int num_masks;
+    int num_rates;
+    int i;
+
+    num_formats = read_usb_sup_formats(is_playback, supported_formats,
+                                       max_formats);
+    num_masks = read_usb_sup_channel_masks(is_playback, supported_channel_masks,
+                                           max_masks);
+    num_rates = read_usb_sup_sample_rates(is_playback,
+                                          supported_sample_rates, max_rates);
+
+#define LUT(table, len, what, dflt)                  \
+    for (i=0; i<len && (table[i] != what); i++);    \
+    if (i==len) { ret |= (what == dflt ? 0 : -1); what=table[0]; }
+
+    LUT(supported_formats, num_formats, *format, AUDIO_FORMAT_DEFAULT);
+    LUT(supported_channel_masks, num_masks, *mask, AUDIO_CHANNEL_NONE);
+    LUT(supported_sample_rates, num_rates, *rate, 0);
+
+#undef LUT
+    return ret < 0 ? -EINVAL : 0; // HACK TBD
+}
+
 static audio_usecase_t get_voice_usecase_id_from_list(struct audio_device *adev)
 {
     struct audio_usecase *usecase;
@@ -1186,6 +1301,9 @@
         return -EINVAL;
     }
 
+    /* Close in-call recording streams */
+    voice_check_and_stop_incall_rec_usecase(adev, in);
+
     /* 1. Disable stream specific mixer controls */
     disable_audio_route(adev, uc_info);
 
@@ -1218,6 +1336,13 @@
         goto error_config;
     }
 
+    /* Check if source matches incall recording usecase criteria */
+    ret = voice_check_and_set_incall_rec_usecase(adev, in);
+    if (ret)
+        goto error_config;
+    else
+        ALOGV("%s: usecase(%d)", __func__, in->usecase);
+
     in->pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE);
     if (in->pcm_device_id < 0) {
         ALOGE("%s: Could not find PCM device id for the usecase(%d)",
@@ -1500,8 +1625,8 @@
                       __func__);
                 ret = false;
                 break;
-            } else if (usecase->id == USECASE_AUDIO_PLAYBACK_MULTI_CH) {
-                ALOGV("%s: multi channel playback is active, "
+            } else if (usecase->id == USECASE_AUDIO_PLAYBACK_HIFI) {
+                ALOGV("%s: hifi playback is active, "
                       "no change in HDMI channels", __func__);
                 ret = false;
                 break;
@@ -1738,7 +1863,9 @@
                                   audio_format_t format,
                                   int channel_count)
 {
-    if ((format != AUDIO_FORMAT_PCM_16_BIT) && (format != AUDIO_FORMAT_PCM_8_24_BIT)) {
+    if ((format != AUDIO_FORMAT_PCM_16_BIT) &&
+        (format != AUDIO_FORMAT_PCM_8_24_BIT) &&
+        (format != AUDIO_FORMAT_PCM_24_BIT_PACKED)) {
         ALOGE("%s: unsupported AUDIO FORMAT (%d) ", __func__, format);
         return -EINVAL;
     }
@@ -1759,6 +1886,7 @@
     case 32000:
     case 44100:
     case 48000:
+    case 96000:
         break;
     default:
         ALOGE("%s: unsupported (%d) samplerate passed ", __func__, sample_rate);
@@ -2062,28 +2190,25 @@
     return status;
 }
 
-static char* out_get_parameters(const struct audio_stream *stream, const char *keys)
-{
-    struct stream_out *out = (struct stream_out *)stream;
-    struct str_parms *query = str_parms_create_str(keys);
-    char *str;
+static bool stream_get_parameter_channels(struct str_parms *query,
+                                          struct str_parms *reply,
+                                          audio_channel_mask_t *supported_channel_masks) {
+    int ret = -1;
     char value[256];
-    struct str_parms *reply = str_parms_create();
-    size_t i, j;
-    int ret;
     bool first = true;
-    ALOGV("%s: enter: keys - %s", __func__, keys);
-    ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value, sizeof(value));
-    if (ret >= 0) {
+    size_t i, j;
+
+    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
+        ret = 0;
         value[0] = '\0';
         i = 0;
-        while (out->supported_channel_masks[i] != 0) {
-            for (j = 0; j < ARRAY_SIZE(out_channels_name_to_enum_table); j++) {
-                if (out_channels_name_to_enum_table[j].value == out->supported_channel_masks[i]) {
+        while (supported_channel_masks[i] != 0) {
+            for (j = 0; j < ARRAY_SIZE(channels_name_to_enum_table); j++) {
+                if (channels_name_to_enum_table[j].value == supported_channel_masks[i]) {
                     if (!first) {
                         strcat(value, "|");
                     }
-                    strcat(value, out_channels_name_to_enum_table[j].name);
+                    strcat(value, channels_name_to_enum_table[j].name);
                     first = false;
                     break;
                 }
@@ -2091,6 +2216,93 @@
             i++;
         }
         str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value);
+    }
+    return ret >= 0;
+}
+
+static bool stream_get_parameter_formats(struct str_parms *query,
+                                         struct str_parms *reply,
+                                         audio_format_t *supported_formats) {
+    int ret = -1;
+    char value[256];
+    int i;
+
+    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
+        ret = 0;
+        value[0] = '\0';
+        switch (supported_formats[0]) {
+            case AUDIO_FORMAT_PCM_16_BIT:
+                strcat(value, "AUDIO_FORMAT_PCM_16_BIT");
+                break;
+            case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+                strcat(value, "AUDIO_FORMAT_PCM_24_BIT_PACKED");
+                break;
+            case AUDIO_FORMAT_PCM_32_BIT:
+                strcat(value, "AUDIO_FORMAT_PCM_32_BIT");
+                break;
+            default:
+                ALOGE("%s: unsupported format %#x", __func__,
+                      supported_formats[0]);
+                break;
+        }
+        str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value);
+    }
+    return ret >= 0;
+}
+
+static bool stream_get_parameter_rates(struct str_parms *query,
+                                       struct str_parms *reply,
+                                       uint32_t *supported_sample_rates) {
+
+    int i;
+    char value[256];
+    int ret = -1;
+    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) {
+        ret = 0;
+        value[0] = '\0';
+        i=0;
+        int cursor = 0;
+        while (supported_sample_rates[i]) {
+            int avail = sizeof(value) - cursor;
+            ret = snprintf(value + cursor, avail, "%s%d",
+                           cursor > 0 ? "|" : "",
+                           supported_sample_rates[i]);
+            if (ret < 0 || ret >= avail) {
+                // if cursor is at the last element of the array
+                //    overwrite with \0 is duplicate work as
+                //    snprintf already put a \0 in place.
+                // else
+                //    we had space to write the '|' at value[cursor]
+                //    (which will be overwritten) or no space to fill
+                //    the first element (=> cursor == 0)
+                value[cursor] = '\0';
+                break;
+            }
+            cursor += ret;
+            ++i;
+        }
+        str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES,
+                          value);
+    }
+    return ret >= 0;
+}
+
+static char* out_get_parameters(const struct audio_stream *stream, const char *keys)
+{
+    struct stream_out *out = (struct stream_out *)stream;
+    struct str_parms *query = str_parms_create_str(keys);
+    char *str;
+    struct str_parms *reply = str_parms_create();
+    bool replied = false;
+    ALOGV("%s: enter: keys - %s", __func__, keys);
+
+    replied |= stream_get_parameter_channels(query, reply,
+                                             &out->supported_channel_masks[0]);
+    replied |= stream_get_parameter_formats(query, reply,
+                                            &out->supported_formats[0]);
+    replied |= stream_get_parameter_rates(query, reply,
+                                          &out->supported_sample_rates[0]);
+    if (replied) {
         str = str_parms_to_str(reply);
     } else {
         str = strdup("");
@@ -2128,7 +2340,7 @@
     struct stream_out *out = (struct stream_out *)stream;
     int volume[2];
 
-    if (out->usecase == USECASE_AUDIO_PLAYBACK_MULTI_CH) {
+    if (out->usecase == USECASE_AUDIO_PLAYBACK_HIFI) {
         /* only take left channel into account: the API is for stereo anyway */
         out->muted = (left == 0.0f);
         return 0;
@@ -2812,10 +3024,31 @@
     return status;
 }
 
-static char* in_get_parameters(const struct audio_stream *stream __unused,
-                               const char *keys __unused)
+static char* in_get_parameters(const struct audio_stream *stream,
+                               const char *keys)
 {
-    return strdup("");
+    struct stream_in *in = (struct stream_in *)stream;
+    struct str_parms *query = str_parms_create_str(keys);
+    char *str;
+    struct str_parms *reply = str_parms_create();
+    bool replied = false;
+
+    ALOGV("%s: enter: keys - %s", __func__, keys);
+    replied |= stream_get_parameter_channels(query, reply,
+                                             &in->supported_channel_masks[0]);
+    replied |= stream_get_parameter_formats(query, reply,
+                                            &in->supported_formats[0]);
+    replied |= stream_get_parameter_rates(query, reply,
+                                          &in->supported_sample_rates[0]);
+    if (replied) {
+        str = str_parms_to_str(reply);
+    } else {
+        str = strdup(keys);
+    }
+    str_parms_destroy(query);
+    str_parms_destroy(reply);
+    ALOGV("%s: exit: returns - %s", __func__, str);
+    return str;
 }
 
 static int in_set_gain(struct audio_stream_in *stream __unused, float gain __unused)
@@ -3201,6 +3434,10 @@
     struct audio_device *adev = (struct audio_device *)dev;
     struct stream_out *out;
     int i, ret;
+    bool is_hdmi = devices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+    bool is_usb_dev = audio_is_usb_out_device(devices) &&
+                      (devices != AUDIO_DEVICE_OUT_USB_ACCESSORY);
+    bool direct_dev = is_hdmi || is_usb_dev;
 
     ALOGV("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x) flags(%#x)",
           __func__, config->sample_rate, config->channel_mask, devices, flags);
@@ -3220,30 +3457,47 @@
     out->handle = handle;
 
     /* Init use case and pcm_config */
-    if (out->flags & AUDIO_OUTPUT_FLAG_DIRECT &&
-            !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
-        out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+    if (audio_is_linear_pcm(out->format) &&
+        (out->flags == AUDIO_OUTPUT_FLAG_NONE ||
+         out->flags == AUDIO_OUTPUT_FLAG_DIRECT) && direct_dev) {
         pthread_mutex_lock(&adev->lock);
-        ret = read_hdmi_channel_masks(out);
+        if (is_hdmi) {
+            ret = read_hdmi_channel_masks(out);
+            if (config->sample_rate == 0)
+                config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
+            if (config->channel_mask == 0)
+                config->channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
+            if (config->format == AUDIO_FORMAT_DEFAULT)
+                config->format = AUDIO_FORMAT_PCM_16_BIT;
+        } else if (is_usb_dev) {
+            ret = read_usb_sup_params_and_compare(true /*is_playback*/,
+                                                  &config->format,
+                                                  &out->supported_formats[0],
+                                                  MAX_SUPPORTED_FORMATS,
+                                                  &config->channel_mask,
+                                                  &out->supported_channel_masks[0],
+                                                  MAX_SUPPORTED_CHANNEL_MASKS,
+                                                  &config->sample_rate,
+                                                  &out->supported_sample_rates[0],
+                                                  MAX_SUPPORTED_SAMPLE_RATES);
+            ALOGV("plugged dev USB ret %d", ret);
+        } else {
+            ret = -1;
+        }
         pthread_mutex_unlock(&adev->lock);
         if (ret != 0)
             goto error_open;
 
-        if (config->sample_rate == 0)
-            config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
-        if (config->channel_mask == 0)
-            config->channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
-        if (config->format == AUDIO_FORMAT_DEFAULT)
-            config->format = AUDIO_FORMAT_PCM_16_BIT;
-
         out->channel_mask = config->channel_mask;
         out->sample_rate = config->sample_rate;
         out->format = config->format;
-        out->usecase = USECASE_AUDIO_PLAYBACK_MULTI_CH;
-        out->config = pcm_config_hdmi_multi;
+        out->usecase = USECASE_AUDIO_PLAYBACK_HIFI;
+        // does this change?
+        out->config = is_hdmi ? pcm_config_hdmi_multi : pcm_config_hifi;
         out->config.rate = config->sample_rate;
         out->config.channels = audio_channel_count_from_out_mask(out->channel_mask);
         out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels * 2);
+        out->config.format = pcm_format_from_audio_format(out->format);
     } else if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
         pthread_mutex_lock(&adev->lock);
         bool offline = (adev->card_status == CARD_STATUS_OFFLINE);
@@ -3305,24 +3559,16 @@
                 __func__, config->offload_info.version,
                 config->offload_info.bit_rate);
     } else  if (out->devices == AUDIO_DEVICE_OUT_TELEPHONY_TX) {
-        if (config->sample_rate == 0)
-            config->sample_rate = AFE_PROXY_SAMPLING_RATE;
-        if (config->sample_rate != 48000 && config->sample_rate != 16000 &&
-                config->sample_rate != 8000) {
-            config->sample_rate = AFE_PROXY_SAMPLING_RATE;
-            ret = -EINVAL;
-            goto error_open;
+        switch (config->sample_rate) {
+            case 8000:
+            case 16000:
+            case 48000:
+                out->sample_rate = config->sample_rate;
+                break;
+            default:
+                out->sample_rate = AFE_PROXY_SAMPLING_RATE;
         }
-        out->sample_rate = config->sample_rate;
-        out->config.rate = config->sample_rate;
-        if (config->format == AUDIO_FORMAT_DEFAULT)
-            config->format = AUDIO_FORMAT_PCM_16_BIT;
-        if (config->format != AUDIO_FORMAT_PCM_16_BIT) {
-            config->format = AUDIO_FORMAT_PCM_16_BIT;
-            ret = -EINVAL;
-            goto error_open;
-        }
-        out->format = config->format;
+        out->format = AUDIO_FORMAT_PCM_16_BIT;
         out->usecase = USECASE_AUDIO_PLAYBACK_AFE_PROXY;
         out->config = pcm_config_afe_proxy_playback;
         adev->voice_tx_output = out;
@@ -3365,6 +3611,19 @@
         }
         out->sample_rate = out->config.rate;
     }
+
+    if ((config->sample_rate != 0 && config->sample_rate != out->sample_rate) ||
+        (config->format != AUDIO_FORMAT_DEFAULT && config->format != out->format) ||
+        (config->channel_mask != 0 && config->channel_mask != out->channel_mask)) {
+        ALOGI("%s: Unsupported output config. sample_rate:%u format:%#x channel_mask:%#x",
+              __func__, config->sample_rate, config->format, config->channel_mask);
+        config->sample_rate = out->sample_rate;
+        config->format = out->format;
+        config->channel_mask = out->channel_mask;
+        ret = -EINVAL;
+        goto error_open;
+    }
+
     ALOGV("%s: Usecase(%s) config->format %#x  out->config.format %#x\n",
             __func__, use_case_table[out->usecase], config->format, out->config.format);
 
@@ -3728,6 +3987,42 @@
             false /* is_low_latency: since we don't know, be conservative */);
 }
 
+static bool adev_input_allow_hifi_record(struct audio_device *adev,
+                                         audio_devices_t devices,
+                                         audio_input_flags_t flags,
+                                         audio_source_t source) {
+    const bool allowed = true;
+
+    if (!audio_is_usb_in_device(devices))
+        return !allowed;
+
+    switch (flags) {
+        case AUDIO_INPUT_FLAG_NONE:
+        case AUDIO_INPUT_FLAG_FAST: // just fast, not fast|raw || fast|mmap
+            break;
+        default:
+            return !allowed;
+    }
+
+    switch (source) {
+        case AUDIO_SOURCE_DEFAULT:
+        case AUDIO_SOURCE_MIC:
+        case AUDIO_SOURCE_UNPROCESSED:
+            break;
+        default:
+            return !allowed;
+    }
+
+    switch (adev->mode) {
+        case 0:
+            break;
+        default:
+            return !allowed;
+    }
+
+    return allowed;
+}
+
 static int adev_open_input_stream(struct audio_hw_device *dev,
                                   audio_io_handle_t handle,
                                   audio_devices_t devices,
@@ -3742,13 +4037,26 @@
     int ret = 0, buffer_size, frame_size;
     int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
     bool is_low_latency = false;
-
-    ALOGV("%s: enter", __func__);
+    bool is_usb_dev = audio_is_usb_in_device(devices);
+    bool may_use_hifi_record = adev_input_allow_hifi_record(adev,
+                                                            devices,
+                                                            flags,
+                                                            source);
+    ALOGE("%s: enter", __func__);
     *stream_in = NULL;
+
+    if (config->sample_rate == 0)
+        config->sample_rate = DEFAULT_INPUT_SAMPLING_RATE;
+    if (config->channel_mask == AUDIO_CHANNEL_NONE)
+        config->channel_mask = AUDIO_CHANNEL_IN_MONO;
+    if (config->format == AUDIO_FORMAT_DEFAULT)
+        config->format = AUDIO_FORMAT_PCM_16_BIT;
+
     if (check_input_parameters(config->sample_rate, config->format, channel_count) != 0)
         return -EINVAL;
 
-    if (audio_extn_tfa_98xx_is_supported() && (audio_extn_hfp_is_active(adev) || voice_is_in_call(adev)))
+    if (audio_extn_tfa_98xx_is_supported() &&
+        (audio_extn_hfp_is_active(adev) || voice_is_in_call(adev)))
         return -EINVAL;
 
     in = (struct stream_in *)calloc(1, sizeof(struct stream_in));
@@ -3781,9 +4089,24 @@
     in->capture_handle = handle;
     in->flags = flags;
 
-    // restrict 24 bit capture for unprocessed source only
-    // for other sources if 24 bit requested reject 24 and set 16 bit capture only
-    if (config->format == AUDIO_FORMAT_DEFAULT) {
+    if (is_usb_dev && may_use_hifi_record) {
+        /* HiFi record selects an appropriate format, channel, rate combo
+           depending on sink capabilities*/
+        ret = read_usb_sup_params_and_compare(false /*is_playback*/,
+                                              &config->format,
+                                              &in->supported_formats[0],
+                                              MAX_SUPPORTED_FORMATS,
+                                              &config->channel_mask,
+                                              &in->supported_channel_masks[0],
+                                              MAX_SUPPORTED_CHANNEL_MASKS,
+                                              &config->sample_rate,
+                                              &in->supported_sample_rates[0],
+                                              MAX_SUPPORTED_SAMPLE_RATES);
+        if (ret != 0) {
+            ret = -EINVAL;
+            goto err_open;
+        }
+    } else if (config->format == AUDIO_FORMAT_DEFAULT) {
         config->format = AUDIO_FORMAT_PCM_16_BIT;
     } else if (config->format == AUDIO_FORMAT_PCM_FLOAT ||
                config->format == AUDIO_FORMAT_PCM_24_BIT_PACKED ||
@@ -3834,6 +4157,18 @@
         in->usecase = USECASE_AUDIO_RECORD_AFE_PROXY;
         in->config = pcm_config_afe_proxy_record;
         in->af_period_multiplier = 1;
+    } else if (is_usb_dev && may_use_hifi_record) {
+        in->usecase = USECASE_AUDIO_RECORD_HIFI;
+        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,
+                                            false /*is_low_latency*/);
+        in->config.period_size = buffer_size / frame_size;
+        in->config.rate = config->sample_rate;
+        in->af_period_multiplier = 1;
+        in->config.format = pcm_format_from_audio_format(config->format);
     } else {
         in->usecase = USECASE_AUDIO_RECORD;
         if (config->sample_rate == LOW_LATENCY_CAPTURE_SAMPLE_RATE &&
@@ -3849,7 +4184,7 @@
                 buffer_size = get_input_buffer_size(config->sample_rate,
                                                     config->format,
                                                     channel_count,
-                                                   is_low_latency);
+                                                    is_low_latency);
                 in->config.period_size = buffer_size / frame_size;
                 in->config.rate = config->sample_rate;
                 in->af_period_multiplier = 1;
@@ -3860,6 +4195,7 @@
             }
         } else if ((config->sample_rate == LOW_LATENCY_CAPTURE_SAMPLE_RATE) &&
                 ((in->flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0)) {
+            // FIXME: Add support for multichannel capture over USB using MMAP
             in->usecase = USECASE_AUDIO_RECORD_MMAP;
             in->config = pcm_config_mmap_capture;
             in->stream.start = in_start;
@@ -3946,13 +4282,13 @@
      *
      * [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {0, 0},
      * [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {15, 15},
-     * [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {1, 1},
+     * [USECASE_AUDIO_PLAYBACK_HIFI] = {1, 1},
      * [USECASE_AUDIO_PLAYBACK_OFFLOAD] = {9, 9},
      * [USECASE_AUDIO_RECORD] = {0, 0},
      * [USECASE_AUDIO_RECORD_LOW_LATENCY] = {15, 15},
      * [USECASE_VOICE_CALL] = {2, 2},
      *
-     * USECASE_AUDIO_PLAYBACK_OFFLOAD, USECASE_AUDIO_PLAYBACK_MULTI_CH omitted.
+     * USECASE_AUDIO_PLAYBACK_OFFLOAD, USECASE_AUDIO_PLAYBACK_HIFI omitted.
      * USECASE_VOICE_CALL omitted, but possible for either input or output.
      */
 
@@ -4289,7 +4625,8 @@
         }
     }
 
-    audio_extn_utils_send_default_app_type_cfg(adev->platform, adev->mixer);
+    // commented as full set of app type cfg is sent from platform
+    // audio_extn_utils_send_default_app_type_cfg(adev->platform, adev->mixer);
     audio_device_ref_count++;
 
     if (property_get("audio_hal.period_multiplier", value, NULL) > 0) {
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index ca068e2..b1e5e45 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -50,7 +50,7 @@
 #define ACDB_DEV_TYPE_OUT 1
 #define ACDB_DEV_TYPE_IN 2
 
-#define MAX_SUPPORTED_CHANNEL_MASKS 2
+#define MAX_SUPPORTED_CHANNEL_MASKS 8
 #define MAX_SUPPORTED_FORMATS 15
 #define MAX_SUPPORTED_SAMPLE_RATES 7
 #define DEFAULT_HDMI_OUT_CHANNELS   2
@@ -82,7 +82,7 @@
     /* Playback usecases */
     USECASE_AUDIO_PLAYBACK_DEEP_BUFFER = 0,
     USECASE_AUDIO_PLAYBACK_LOW_LATENCY,
-    USECASE_AUDIO_PLAYBACK_MULTI_CH,
+    USECASE_AUDIO_PLAYBACK_HIFI,
     USECASE_AUDIO_PLAYBACK_OFFLOAD,
     USECASE_AUDIO_PLAYBACK_TTS,
     USECASE_AUDIO_PLAYBACK_ULL,
@@ -96,6 +96,7 @@
     USECASE_AUDIO_RECORD,
     USECASE_AUDIO_RECORD_LOW_LATENCY,
     USECASE_AUDIO_RECORD_MMAP,
+    USECASE_AUDIO_RECORD_HIFI,
 
     /* Voice extension usecases
      *
@@ -167,6 +168,12 @@
     int data[];
 };
 
+struct stream_app_type_cfg {
+    int sample_rate;
+    uint32_t bit_width;
+    int app_type;
+};
+
 struct stream_out {
     struct audio_stream_out stream;
     pthread_mutex_t lock; /* see note below on mutex acquisition order */
@@ -186,9 +193,12 @@
     audio_usecase_t usecase;
     /* Array of supported channel mask configurations. +1 so that the last entry is always 0 */
     audio_channel_mask_t supported_channel_masks[MAX_SUPPORTED_CHANNEL_MASKS + 1];
+    audio_format_t supported_formats[MAX_SUPPORTED_FORMATS + 1];
+    uint32_t supported_sample_rates[MAX_SUPPORTED_SAMPLE_RATES + 1];
     bool muted;
     uint64_t written; /* total frames written, not cleared when entering standby */
     audio_io_handle_t handle;
+    struct stream_app_type_cfg app_type_cfg;
 
     int non_blocking;
     int playback_started;
@@ -237,13 +247,22 @@
     audio_format_t format;
     card_status_t card_status;
     int capture_started;
+
+    struct stream_app_type_cfg app_type_cfg;
+
+    /* Array of supported channel mask configurations.
+       +1 so that the last entry is always 0 */
+    audio_channel_mask_t supported_channel_masks[MAX_SUPPORTED_CHANNEL_MASKS + 1];
+    audio_format_t supported_formats[MAX_SUPPORTED_FORMATS + 1];
+    uint32_t supported_sample_rates[MAX_SUPPORTED_SAMPLE_RATES + 1];
 };
 
 typedef enum usecase_type_t {
     PCM_PLAYBACK,
     PCM_CAPTURE,
     VOICE_CALL,
-    PCM_HFP_CALL
+    PCM_HFP_CALL,
+    USECASE_TYPE_MAX
 } usecase_type_t;
 
 union stream_ptr {
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 2fe6168..aa3419d 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -157,7 +157,7 @@
                                             DEEP_BUFFER_PCM_DEVICE},
     [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
                                            LOWLATENCY_PCM_DEVICE},
-    [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {MULTIMEDIA2_PCM_DEVICE,
+    [USECASE_AUDIO_PLAYBACK_HIFI] = {MULTIMEDIA2_PCM_DEVICE,
                                         MULTIMEDIA2_PCM_DEVICE},
     [USECASE_AUDIO_PLAYBACK_OFFLOAD] =
                      {PLAYBACK_OFFLOAD_DEVICE, PLAYBACK_OFFLOAD_DEVICE},
@@ -215,6 +215,7 @@
     [SND_DEVICE_OUT_VOICE_TX] = "voice-tx",
     [SND_DEVICE_OUT_AFE_PROXY] = "afe-proxy",
     [SND_DEVICE_OUT_USB_HEADSET] = "usb-headphones",
+    [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",
@@ -302,6 +303,7 @@
     [SND_DEVICE_OUT_VOICE_TX] = 45,
     [SND_DEVICE_OUT_AFE_PROXY] = 0,
     [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,
@@ -396,6 +398,7 @@
     {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_TX)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_AFE_PROXY)},
     {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)},
@@ -462,7 +465,7 @@
 static struct name_to_index usecase_name_index[AUDIO_USECASE_MAX] = {
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_DEEP_BUFFER)},
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_LOW_LATENCY)},
-    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_MULTI_CH)},
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_HIFI)},
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD)},
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_ULL)},
     {TO_NAME_INDEX(USECASE_AUDIO_RECORD)},
@@ -663,6 +666,7 @@
     backend_table[SND_DEVICE_IN_VOICE_RX] = strdup("afe-proxy");
     backend_table[SND_DEVICE_OUT_AFE_PROXY] = strdup("afe-proxy");
     backend_table[SND_DEVICE_OUT_USB_HEADSET] = strdup("usb-headphones");
+    backend_table[SND_DEVICE_OUT_USB_HEADPHONES] = strdup("usb-headphones");
     backend_table[SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] =
         strdup("speaker-and-usb-headphones");
     backend_table[SND_DEVICE_IN_USB_HEADSET_MIC] = strdup("usb-headset-mic");
@@ -2294,3 +2298,36 @@
 {
     return -1;
 }
+
+int platform_send_audio_calibration_v2(void *platform __unused,
+                                       struct audio_usecase *usecase __unused,
+                                       int app_type __unused,
+                                       int sample_rate __unused)
+{
+    return -ENOSYS;
+}
+
+void platform_check_and_update_copp_sample_rate(void* platform __unused,
+                                               snd_device_t snd_device __unused,
+                                                unsigned int stream_sr __unused,
+                                                int* sample_rate __unused)
+{
+
+}
+
+int platform_get_snd_device_backend_index(snd_device_t snd_device __unused)
+{
+    return -ENOSYS;
+}
+
+bool platform_supports_app_type_cfg() { return false; }
+
+void platform_add_app_type(int bw __unused, const char *uc_type __unused,
+                           int app_type __unused, int max_sr __unused) {}
+
+int platform_get_app_type_v2(void *platform __unused,
+                             enum usecase_type_t type __unused,
+                             int bw __unused, int sr __unused,
+                             int *app_type __unused) {
+    return -ENOSYS;
+}
diff --git a/hal/msm8916/platform.h b/hal/msm8916/platform.h
index da4a027..07dc1af 100644
--- a/hal/msm8916/platform.h
+++ b/hal/msm8916/platform.h
@@ -76,6 +76,7 @@
     SND_DEVICE_OUT_VOICE_TX,
     SND_DEVICE_OUT_AFE_PROXY,
     SND_DEVICE_OUT_USB_HEADSET,
+    SND_DEVICE_OUT_USB_HEADPHONES,
     SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET,
     SND_DEVICE_OUT_ANC_HEADSET,
     SND_DEVICE_OUT_ANC_FB_HEADSET,
@@ -156,6 +157,7 @@
 };
 
 #define DEFAULT_OUTPUT_SAMPLING_RATE 48000
+#define DEFAULT_INPUT_SAMPLING_RATE 48000
 
 #define ALL_SESSION_VSID                0xFFFFFFFF
 #define DEFAULT_MUTE_RAMP_DURATION_MS   20
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index 072a1e4..cfae645 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -1133,3 +1133,31 @@
 {
     return -1;
 }
+
+int platform_get_snd_device_backend_index(snd_device_t snd_device)
+{
+    return -ENOSYS;
+}
+
+void platform_check_and_update_copp_sample_rate(void* platform, snd_device_t snd_device,
+                                                unsigned int stream_sr, int* sample_rate)
+{
+
+}
+
+int platform_send_audio_calibration_v2(void *platform, struct audio_usecase *usecase,
+                                       int app_type, int sample_rate)
+{
+    return -ENOSYS;
+}
+
+bool platform_supports_app_type_cfg() { return false; }
+
+void platform_add_app_type(int bw, const char *uc_type,
+                           int app_type, int max_sr) {}
+
+
+int platform_get_app_type_v2(void *platform, enum usecase_type_t type,
+                             int bw, int sr, int *app_type) {
+    return -ENOSYS;
+}
diff --git a/hal/msm8960/platform.h b/hal/msm8960/platform.h
index b879c0b..0835378 100644
--- a/hal/msm8960/platform.h
+++ b/hal/msm8960/platform.h
@@ -96,6 +96,7 @@
 #define SOUND_CARD 0
 #define MIXER_PATH_MAX_LENGTH 100
 #define DEFAULT_OUTPUT_SAMPLING_RATE 48000
+#define DEFAULT_INPUT_SAMPLING_RATE 48000
 
 /*
  * tinyAlsa library interprets period size as number of frames
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 0f3bcf0..02512ea 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -24,6 +24,7 @@
 #include <cutils/properties.h>
 #include <audio_hw.h>
 #include <platform_api.h>
+#include "acdb.h"
 #include "platform.h"
 #include "audio_extn.h"
 #include <linux/msm_audio.h>
@@ -54,14 +55,10 @@
 /* EDID format ID for LPCM audio */
 #define EDID_FORMAT_LPCM    1
 
-/* Retry for delay in FW loading*/
-#define RETRY_NUMBER 10
-#define RETRY_US 500000
-#define MAX_SND_CARD 8
-
 #define MAX_SND_CARD_NAME_LEN 31
 
-#define DEFAULT_APP_TYPE_RX_PATH  0x11130
+#define DEFAULT_APP_TYPE_RX_PATH  69936
+#define DEFAULT_APP_TYPE_TX_PATH  69938
 
 #define TOSTRING_(x) #x
 #define TOSTRING(x) TOSTRING_(x)
@@ -93,21 +90,18 @@
     int acdb_id;
 };
 
+#define BE_DAI_NAME_MAX_LENGTH 24
+struct be_dai_name_struct {
+    unsigned int be_id;
+    char be_name[BE_DAI_NAME_MAX_LENGTH];
+};
+
 static struct listnode operator_info_list;
 static struct listnode *operator_specific_device_table[SND_DEVICE_MAX];
 
 /* Audio calibration related functions */
-typedef void (*acdb_deallocate_t)();
-typedef int  (*acdb_init_v2_cvd_t)(char *, char *, int);
-typedef int  (*acdb_init_v2_t)(char *);
-typedef int  (*acdb_init_t)();
-typedef void (*acdb_send_audio_cal_t)(int, int);
-typedef void (*acdb_send_voice_cal_t)(int, int);
-typedef int (*acdb_reload_vocvoltable_t)(int);
-typedef int (*acdb_send_gain_dep_cal_t)(int, int, int, int, int);
-typedef int (*acdb_send_custom_top_t) (void);
+typedef void (*acdb_send_audio_cal_v3_t)(int, int, int, int, int);
 
-/* Audio calibration related functions */
 struct platform_data {
     struct audio_device *adev;
     bool fluence_in_spkr_mode;
@@ -129,6 +123,7 @@
 #endif
     acdb_deallocate_t          acdb_deallocate;
     acdb_send_audio_cal_t      acdb_send_audio_cal;
+    acdb_send_audio_cal_v3_t   acdb_send_audio_cal_v3;
     acdb_send_voice_cal_t      acdb_send_voice_cal;
     acdb_reload_vocvoltable_t  acdb_reload_vocvoltable;
     acdb_send_gain_dep_cal_t   acdb_send_gain_dep_cal;
@@ -151,7 +146,7 @@
                                             DEEP_BUFFER_PCM_DEVICE},
     [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {LOWLATENCY_PCM_DEVICE,
                                             LOWLATENCY_PCM_DEVICE},
-    [USECASE_AUDIO_PLAYBACK_MULTI_CH] = {MULTIMEDIA2_PCM_DEVICE,
+    [USECASE_AUDIO_PLAYBACK_HIFI] = {MULTIMEDIA2_PCM_DEVICE,
                                          MULTIMEDIA2_PCM_DEVICE},
     [USECASE_AUDIO_PLAYBACK_OFFLOAD] = {PLAYBACK_OFFLOAD_DEVICE,
                                         PLAYBACK_OFFLOAD_DEVICE},
@@ -170,6 +165,9 @@
     [USECASE_AUDIO_RECORD_MMAP] = {MMAP_RECORD_PCM_DEVICE,
             MMAP_RECORD_PCM_DEVICE},
 
+    [USECASE_AUDIO_RECORD_HIFI] = {MULTIMEDIA2_PCM_DEVICE,
+                                   MULTIMEDIA2_PCM_DEVICE},
+
     [USECASE_VOICE_CALL] = {VOICE_CALL_PCM_DEVICE,
                             VOICE_CALL_PCM_DEVICE},
     [USECASE_VOICE2_CALL] = {VOICE2_CALL_PCM_DEVICE, VOICE2_CALL_PCM_DEVICE},
@@ -231,7 +229,9 @@
     [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_VOICE_USB_HEADSET] = "usb-headset",
     [SND_DEVICE_OUT_USB_HEADPHONES] = "usb-headphones",
+    [SND_DEVICE_OUT_VOICE_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",
@@ -289,6 +289,10 @@
     [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_USB_HEADSET_MIC] ="usb-headset-mic",
+    [SND_DEVICE_IN_USB_HEADSET_MIC_AEC] = "usb-headset-mic",
+    [SND_DEVICE_IN_UNPROCESSED_USB_HEADSET_MIC] = "usb-headset-mic",
+    [SND_DEVICE_IN_VOICE_RECOG_USB_HEADSET_MIC] = "usb-headset-mic",
     [SND_DEVICE_IN_VOICE_REC_HEADSET_MIC] = "headset-mic",
 
     [SND_DEVICE_IN_UNPROCESSED_MIC] = "unprocessed-mic",
@@ -338,7 +342,9 @@
     [SND_DEVICE_OUT_VOICE_TTY_VCO_USB] = 17,
     [SND_DEVICE_OUT_VOICE_TX] = 45,
     [SND_DEVICE_OUT_USB_HEADSET] = 45,
+    [SND_DEVICE_OUT_VOICE_USB_HEADSET] = 45,
     [SND_DEVICE_OUT_USB_HEADPHONES] = 45,
+    [SND_DEVICE_OUT_VOICE_USB_HEADPHONES] = 45,
     [SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET] = 14,
     [SND_DEVICE_OUT_SPEAKER_PROTECTED] = 124,
     [SND_DEVICE_OUT_VOICE_SPEAKER_PROTECTED] = 101,
@@ -402,6 +408,10 @@
 
     [SND_DEVICE_IN_VOICE_RX] = 44,
     [SND_DEVICE_IN_USB_HEADSET_MIC] = 44,
+    [SND_DEVICE_IN_VOICE_USB_HEADSET_MIC] = 44,
+    [SND_DEVICE_IN_UNPROCESSED_USB_HEADSET_MIC] = 44,
+    [SND_DEVICE_IN_VOICE_RECOG_USB_HEADSET_MIC] = 44,
+    [SND_DEVICE_IN_USB_HEADSET_MIC_AEC] = 44,
     [SND_DEVICE_IN_THREE_MIC] = 46,
     [SND_DEVICE_IN_QUAD_MIC] = 46,
     [SND_DEVICE_IN_CAPTURE_VI_FEEDBACK] = 102,
@@ -453,7 +463,9 @@
     {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_VOICE_USB_HEADSET)},
     {TO_NAME_INDEX(SND_DEVICE_OUT_USB_HEADPHONES)},
+    {TO_NAME_INDEX(SND_DEVICE_OUT_VOICE_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)},
@@ -510,6 +522,10 @@
     {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_VOICE_USB_HEADSET_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_UNPROCESSED_USB_HEADSET_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_VOICE_RECOG_USB_HEADSET_MIC)},
+    {TO_NAME_INDEX(SND_DEVICE_IN_USB_HEADSET_MIC_AEC)},
 
     {TO_NAME_INDEX(SND_DEVICE_IN_UNPROCESSED_MIC)},
     {TO_NAME_INDEX(SND_DEVICE_IN_UNPROCESSED_HEADSET_MIC)},
@@ -532,7 +548,7 @@
 static const struct name_to_index usecase_name_index[AUDIO_USECASE_MAX] = {
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_DEEP_BUFFER)},
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_LOW_LATENCY)},
-    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_MULTI_CH)},
+    {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_HIFI)},
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_OFFLOAD)},
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_TTS)},
     {TO_NAME_INDEX(USECASE_AUDIO_PLAYBACK_ULL)},
@@ -540,6 +556,7 @@
     {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_AUDIO_RECORD_HIFI)},
     {TO_NAME_INDEX(USECASE_VOICE_CALL)},
     {TO_NAME_INDEX(USECASE_VOICE2_CALL)},
     {TO_NAME_INDEX(USECASE_VOLTE_CALL)},
@@ -558,6 +575,23 @@
     {TO_NAME_INDEX(USECASE_AUDIO_DSM_FEEDBACK)},
 };
 
+static const struct name_to_index usecase_type_index[USECASE_TYPE_MAX] = {
+    {TO_NAME_INDEX(PCM_PLAYBACK)},
+    {TO_NAME_INDEX(PCM_CAPTURE)},
+    {TO_NAME_INDEX(VOICE_CALL)},
+    {TO_NAME_INDEX(PCM_HFP_CALL)},
+};
+
+struct app_type_entry {
+    int uc_type;
+    int bit_width;
+    int app_type;
+    int max_rate;
+    struct listnode node; // membership in app_type_entry_list;
+};
+
+static struct listnode app_type_entry_list;
+
 #define DEEP_BUFFER_PLATFORM_DELAY (29*1000LL)
 #define LOW_LATENCY_PLATFORM_DELAY (13*1000LL)
 #define ULL_PLATFORM_DELAY         (3*1000LL)
@@ -566,6 +600,8 @@
 static pthread_once_t check_op_once_ctl = PTHREAD_ONCE_INIT;
 static bool is_tmus = false;
 
+static int init_be_dai_name_table(struct audio_device *adev);
+
 static void check_operator()
 {
     char value[PROPERTY_VALUE_MAX];
@@ -667,6 +703,15 @@
     return ret;
 }
 
+inline bool platform_supports_app_type_cfg()
+{
+#ifdef PLATFORM_MSM8998
+    return true;
+#else
+    return false;
+#endif
+}
+
 bool platform_send_gain_dep_cal(void *platform, int level)
 {
     bool ret_val = false;
@@ -952,10 +997,16 @@
     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_VOICE_USB_HEADSET] = strdup("usb-headset");
     backend_tag_table[SND_DEVICE_OUT_USB_HEADPHONES] = strdup("usb-headphones");
+    backend_tag_table[SND_DEVICE_OUT_VOICE_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");
+    backend_tag_table[SND_DEVICE_IN_VOICE_USB_HEADSET_MIC] = strdup("usb-headset-mic");
+    backend_tag_table[SND_DEVICE_IN_UNPROCESSED_USB_HEADSET_MIC] = strdup("usb-headset-mic");
+    backend_tag_table[SND_DEVICE_IN_VOICE_RECOG_USB_HEADSET_MIC] = strdup("usb-headset-mic");
+    backend_tag_table[SND_DEVICE_IN_USB_HEADSET_MIC_AEC] = 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");
@@ -980,11 +1031,27 @@
     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_VOICE_TTY_FULL_USB] = strdup("USB_AUDIO_RX");
+    hw_interface_table[SND_DEVICE_OUT_VOICE_TTY_VCO_USB] = strdup("USB_AUDIO_RX");
+    hw_interface_table[SND_DEVICE_OUT_VOICE_USB_HEADSET] = strdup("USB_AUDIO_RX");
     hw_interface_table[SND_DEVICE_OUT_USB_HEADPHONES] = strdup("USB_AUDIO_RX");
+    hw_interface_table[SND_DEVICE_OUT_VOICE_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");
+    hw_interface_table[SND_DEVICE_IN_USB_HEADSET_MIC] = strdup("USB_AUDIO_TX");
+    hw_interface_table[SND_DEVICE_IN_VOICE_USB_HEADSET_MIC] = strdup("USB_AUDIO_TX");
+    hw_interface_table[SND_DEVICE_IN_USB_HEADSET_MIC_AEC] =  strdup("USB_AUDIO_TX");
+    hw_interface_table[SND_DEVICE_IN_UNPROCESSED_USB_HEADSET_MIC] = strdup("USB_AUDIO_TX");
+    hw_interface_table[SND_DEVICE_IN_VOICE_RECOG_USB_HEADSET_MIC] = strdup("USB_AUDIO_TX");
+    hw_interface_table[SND_DEVICE_IN_VOICE_TTY_FULL_USB_MIC] = strdup("USB_AUDIO_TX");
+    hw_interface_table[SND_DEVICE_IN_VOICE_TTY_HCO_USB_MIC] = strdup("USB_AUDIO_TX");
+    hw_interface_table[SND_DEVICE_IN_SPEAKER_MIC] = strdup("SLIMBUS_0_TX");
+    hw_interface_table[SND_DEVICE_IN_HANDSET_MIC] = strdup("SLIMBUS_0_TX");
+    hw_interface_table[SND_DEVICE_IN_HEADSET_MIC] = strdup("SLIMBUS_0_TX");
+    hw_interface_table[SND_DEVICE_IN_UNPROCESSED_MIC] = strdup("SLIMBUS_0_TX");
+    hw_interface_table[SND_DEVICE_IN_CAMCORDER_MIC] = strdup("SLIMBUS_0_TX");
 
     my_data->max_mic_count = PLATFORM_DEFAULT_MIC_COUNT;
 }
@@ -1100,26 +1167,51 @@
             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]));
+static int
+platform_backend_app_type_cfg_init(struct platform_data *pdata,
+                                   struct mixer *mixer)
+{
+    size_t app_type_cfg[128] = {0};
+    int length, num_app_types = 0;
+    struct mixer_ctl *ctl = NULL;
 
-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;
+    const char *mixer_ctl_name = "App Type Config";
+    ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer cmd - %s",__func__, mixer_ctl_name);
+        return -1;
+    }
+
+    length = 1; // reserve index 0 for number of app types
+
+    struct listnode *node;
+    struct app_type_entry *entry;
+    list_for_each(node, &app_type_entry_list) {
+        entry = node_to_item(node, struct app_type_entry, node);
+        app_type_cfg[length++] = entry->app_type;
+        app_type_cfg[length++] = entry->max_rate;
+        app_type_cfg[length++] = entry->bit_width;
+        ALOGI("%s add entry %d %d", __func__, entry->app_type, entry->bit_width);
+        num_app_types += 1;
+    }
+
+    // default for capture
+    int t;
+    platform_get_default_app_type_v2(pdata,
+                                     PCM_CAPTURE,
+                                     &t);
+    app_type_cfg[length++] = t;
+    app_type_cfg[length++] = 48000;
+    app_type_cfg[length++] = 16;
+    num_app_types += 1;
+
+    if (num_app_types) {
+        app_type_cfg[0] = num_app_types;
+        if (mixer_ctl_set_array(ctl, app_type_cfg, length) < 0) {
+            ALOGE("Failed to set app type cfg");
         }
     }
-    return false;
+    return 0;
 }
 
 void *platform_init(struct audio_device *adev)
@@ -1140,144 +1232,86 @@
     my_data->adev = adev;
 
     list_init(&operator_info_list);
+    list_init(&app_type_entry_list);
 
     set_platform_defaults(my_data);
-    bool card_verifed[MAX_SND_CARD] = {0};
-    const int retry_limit = property_get_int32("audio.snd_card.open.retries", RETRY_NUMBER);
 
-    for (;;) {
-        if (snd_card_num >= MAX_SND_CARD) {
-            if (retry_num++ >= retry_limit) {
-                ALOGE("%s: Unable to find correct sound card, aborting.", __func__);
-                goto init_failed;
-            }
+    // audio_extn_utils_get_snd_card_num does
+    // - open mixer and get snd card name
+    // - parse platform info xml file and check for valid snd card name
+    // - on failure loop through all the active snd card
 
-            snd_card_num = 0;
-            usleep(RETRY_US);
-            continue;
-        }
-
-        if (card_verifed[snd_card_num]) {
-            ++snd_card_num;
-            continue;
-        }
-
-        adev->mixer = mixer_open(snd_card_num);
-
-        if (!adev->mixer) {
-            ALOGE("%s: Unable to open the mixer card: %d", __func__,
-               snd_card_num);
-            ++snd_card_num;
-            continue;
-        }
-
-        card_verifed[snd_card_num] = true;
-
-        snd_card_name = mixer_get_name(adev->mixer);
-        my_data->hw_info = hw_info_init(snd_card_name);
-
-        audio_extn_set_snd_card_split(snd_card_name);
-        snd_split_handle = audio_extn_get_snd_card_split();
-
-        /* Get the codec internal name from the sound card and/or form factor
-         * name and form the mixer paths and platfor info file name dynamically.
-         * This is generic way of picking any codec and forma factor name based
-         * mixer and platform info files in future with no code change.
-
-         * current code extends and looks for any of the exteneded mixer path and
-         * platform info file present based on codec and form factor.
-
-         * order of picking appropriate file is
-         * <i>   mixer_paths_<codec_name>_<form_factor>.xml, if file not present
-         * <ii>  mixer_paths_<codec_name>.xml, if file not present
-         * <iii> mixer_paths.xml
-
-         * same order is followed for audio_platform_info.xml as well
-         */
-
-        // need to carryforward old file name
-        if (!strncmp(snd_card_name, TOMTOM_8226_SND_CARD_NAME,
-                     min(strlen(TOMTOM_8226_SND_CARD_NAME), strlen(snd_card_name)))) {
-            snprintf(mixer_xml_file, sizeof(mixer_xml_file), "%s_%s.xml",
-                             MIXER_XML_BASE_STRING, TOMTOM_MIXER_FILE_SUFFIX );
-        } else {
-
-            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 (!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 (!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);
-                }
-            }
-
-            snprintf(platform_info_file, sizeof(platform_info_file), "%s_%s_%s.xml",
-                             PLATFORM_INFO_XML_BASE_STRING, snd_split_handle->snd_card,
-                             snd_split_handle->form_factor);
-
-            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 (!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);
-                }
-            }
-        }
-
-        /* Initialize platform specific ids and/or backends*/
-        platform_info_init(platform_info_file, my_data);
-
-        /* validate the sound card name
-         * my_data->snd_card_name can contain
-         *     <a> complete sound card name, i.e. <device>-<codec>-<form_factor>-snd-card
-         *         example: msm8994-tomtom-mtp-snd-card
-         *     <b> or sub string of the card name, i.e. <device>-<codec>
-         *         example: msm8994-tomtom
-         * snd_card_name is truncated to 32 charaters as per mixer_get_name() implementation
-         * so use min of my_data->snd_card_name and snd_card_name length for comparison
-         */
-
-        if (my_data->snd_card_name != NULL &&
-                strncmp(snd_card_name, my_data->snd_card_name,
-                        min(strlen(snd_card_name), strlen(my_data->snd_card_name))) != 0) {
-            ALOGI("%s: found valid sound card %s, but not primary sound card %s",
-                   __func__, snd_card_name, my_data->snd_card_name);
-            ++snd_card_num;
-            mixer_close(adev->mixer);
-            adev->mixer = NULL;
-            hw_info_deinit(my_data->hw_info);
-            my_data->hw_info = NULL;
-            continue;
-        }
-        ALOGI("%s: found sound card %s, primary sound card expeted is %s",
-              __func__, snd_card_name, my_data->snd_card_name);
-
-        ALOGD("%s: Loading mixer file: %s", __func__, mixer_xml_file);
-        adev->audio_route = audio_route_init(snd_card_num, mixer_xml_file);
-
-        if (!adev->audio_route) {
-            ALOGE("%s: Failed to init audio route controls, aborting.", __func__);
-            mixer_close(adev->mixer);
-            adev->mixer = NULL;
-            hw_info_deinit(my_data->hw_info);
-            my_data->hw_info = NULL;
-            goto init_failed;
-        }
-        adev->snd_card = snd_card_num;
-        ALOGD("%s: Opened sound card:%d", __func__, snd_card_num);
-        break;
+    snd_card_num = audio_extn_utils_get_snd_card_num();
+    if (-1 == snd_card_num) {
+        ALOGE("%s: invalid sound card number (-1), bailing out ", __func__);
+        goto init_failed;
     }
 
+    adev->mixer = mixer_open(snd_card_num);
+    snd_card_name = mixer_get_name(adev->mixer);
+    my_data->hw_info = hw_info_init(snd_card_name);
+
+    audio_extn_set_snd_card_split(snd_card_name);
+    snd_split_handle = audio_extn_get_snd_card_split();
+
+    /* Get the codec internal name from the sound card and/or form factor
+     * name and form the mixer paths and platfor info file name dynamically.
+     * This is generic way of picking any codec and forma factor name based
+     * mixer and platform info files in future with no code change.
+
+     * current code extends and looks for any of the exteneded mixer path and
+     * platform info file present based on codec and form factor.
+
+     * order of picking appropriate file is
+     * <i>   mixer_paths_<codec_name>_<form_factor>.xml, if file not present
+     * <ii>  mixer_paths_<codec_name>.xml, if file not present
+     * <iii> mixer_paths.xml
+
+     * same order is followed for audio_platform_info.xml as well
+     */
+
+    // need to carryforward old file name
+    if (!strncmp(snd_card_name, TOMTOM_8226_SND_CARD_NAME,
+                 min(strlen(TOMTOM_8226_SND_CARD_NAME), strlen(snd_card_name)))) {
+        snprintf(mixer_xml_file, sizeof(mixer_xml_file), "%s_%s.xml",
+                         MIXER_XML_BASE_STRING, TOMTOM_MIXER_FILE_SUFFIX );
+    } else {
+
+        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 (!audio_extn_utils_resolve_config_file(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 (!audio_extn_utils_resolve_config_file(mixer_xml_file)) {
+                memset(mixer_xml_file, 0, sizeof(mixer_xml_file));
+                strlcpy(mixer_xml_file, MIXER_XML_DEFAULT_PATH, MIXER_PATH_MAX_LENGTH);
+                audio_extn_utils_resolve_config_file(mixer_xml_file);
+            }
+        }
+    }
+
+    audio_extn_utils_get_platform_info(snd_card_name, platform_info_file);
+
+    /* Initialize platform specific ids and/or backends*/
+    platform_info_init(platform_info_file, my_data);
+
+    ALOGD("%s: Loading mixer file: %s", __func__, mixer_xml_file);
+    adev->audio_route = audio_route_init(snd_card_num, mixer_xml_file);
+
+    if (!adev->audio_route) {
+        ALOGE("%s: Failed to init audio route controls, aborting.", __func__);
+        mixer_close(adev->mixer);
+        adev->mixer = NULL;
+        hw_info_deinit(my_data->hw_info);
+        my_data->hw_info = NULL;
+        goto init_failed;
+    }
+    adev->snd_card = snd_card_num;
+    ALOGD("%s: Opened sound card:%d", __func__, snd_card_num);
+
     //set max volume step for voice call
     property_get("ro.config.vc_call_vol_steps", value, TOSTRING(MAX_VOL_INDEX));
     my_data->max_vol_index = atoi(value);
@@ -1360,6 +1394,12 @@
             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_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_v3 from %s",
+                  __func__, LIB_ACDB_LOADER);
+
         my_data->acdb_send_audio_cal = (acdb_send_audio_cal_t)dlsym(my_data->acdb_handle,
                                                     "acdb_loader_send_audio_cal");
         if (!my_data->acdb_send_audio_cal)
@@ -1385,30 +1425,30 @@
                   __func__, LIB_ACDB_LOADER);
 
 #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_init_v2_cvd_t acdb_init_local;
+        acdb_init_local = (acdb_init_v2_cvd_t)dlsym(my_data->acdb_handle,
                                               "acdb_loader_init_v2");
-        if (acdb_init == NULL)
+        if (acdb_init_local == NULL)
             ALOGE("%s: dlsym error %s for acdb_loader_init_v2", __func__,
                   dlerror());
 
 #elif defined (PLATFORM_MSM8084)
-        acdb_init_v2_t acdb_init;
-        acdb_init = (acdb_init_v2_t)dlsym(my_data->acdb_handle,
+        acdb_init_v2_t acdb_init_local;
+        acdb_init_local = (acdb_init_v2_t)dlsym(my_data->acdb_handle,
                                           "acdb_loader_init_v2");
-        if (acdb_init == NULL)
+        if (acdb_init_local == NULL)
             ALOGE("%s: dlsym error %s for acdb_loader_init_v2", __func__,
                   dlerror());
 
 #else
-        acdb_init_t acdb_init;
-        acdb_init = (acdb_init_t)dlsym(my_data->acdb_handle,
+        acdb_init_t acdb_init_local;
+        acdb_init_local = (acdb_init_t)dlsym(my_data->acdb_handle,
                                                     "acdb_loader_init_ACDB");
-        if (acdb_init == NULL)
+        if (acdb_init_local == NULL)
             ALOGE("%s: dlsym error %s for acdb_loader_init_ACDB", __func__,
                   dlerror());
 #endif
-        my_data->acdb_init = acdb_init;
+        my_data->acdb_init = acdb_init_local;
 
         my_data->acdb_send_custom_top = (acdb_send_custom_top_t)
                                         dlsym(my_data->acdb_handle,
@@ -1418,7 +1458,14 @@
             ALOGE("%s: Could not find the symbol acdb_get_default_app_type from %s",
                   __func__, LIB_ACDB_LOADER);
 
-        platform_acdb_init(my_data);
+        int result = acdb_init(adev->snd_card);
+        if (!result) {
+            my_data->acdb_initialized = true;
+            ALOGD("ACDB initialized");
+        } else {
+            my_data->acdb_initialized = false;
+            ALOGD("ACDB initialization failed");
+        }
     }
 
     /* init usb */
@@ -1433,6 +1480,11 @@
 
     platform_backend_config_init(my_data);
 
+    init_be_dai_name_table(adev);
+
+    if (platform_supports_app_type_cfg())
+        platform_backend_app_type_cfg_init(my_data, adev->mixer);
+
     return my_data;
 
 init_failed:
@@ -1446,6 +1498,7 @@
     int32_t dev;
     struct operator_info *info_item;
     struct operator_specific_device *device_item;
+    struct app_type_entry *ap;
     struct listnode *node;
 
     struct platform_data *my_data = (struct platform_data *)platform;
@@ -1483,6 +1536,13 @@
         free(info_item);
     }
 
+    while (!list_empty(&app_type_entry_list)) {
+        node = list_head(&app_type_entry_list);
+        list_remove(node);
+        ap = node_to_item(node, struct app_type_entry, node);
+        free(ap);
+    }
+
     mixer_close(my_data->adev->mixer);
     free(platform);
 
@@ -1668,13 +1728,6 @@
     return ret;
 }
 
-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;
-}
-
 int platform_get_snd_device_acdb_id(snd_device_t snd_device)
 {
     if ((snd_device < SND_DEVICE_MIN) || (snd_device >= SND_DEVICE_MAX)) {
@@ -1725,6 +1778,9 @@
     struct platform_data *my_data = (struct platform_data *)platform;
     int acdb_dev_id, acdb_dev_type;
 
+    if (platform_supports_app_type_cfg()) // use v2 instead
+        return -ENOSYS;
+
     acdb_dev_id = acdb_device_table[audio_extn_get_spkr_prot_snd_device(snd_device)];
     if (acdb_dev_id < 0) {
         ALOGE("%s: Could not find acdb id for device(%d)",
@@ -1744,6 +1800,63 @@
     return 0;
 }
 
+int platform_send_audio_calibration_v2(void *platform, struct audio_usecase *usecase,
+                                       int app_type, int sample_rate)
+{
+    struct platform_data *my_data = (struct platform_data *)platform;
+    int acdb_dev_id, acdb_dev_type;
+    int snd_device = SND_DEVICE_OUT_SPEAKER;
+    int new_snd_device[SND_DEVICE_OUT_END] = {0};
+    int i, num_devices = 1;
+
+    if (!platform_supports_app_type_cfg()) // use v1 instead
+        return -ENOSYS;
+
+    if (usecase->type == PCM_PLAYBACK)
+        snd_device = usecase->out_snd_device;
+    else if (usecase->type == PCM_CAPTURE)
+        snd_device = usecase->in_snd_device;
+
+    // skipped over get_spkr_prot_device
+    acdb_dev_id = acdb_device_table[snd_device];
+    if (acdb_dev_id < 0) {
+        ALOGE("%s: Could not find acdb id for device(%d)",
+              __func__, snd_device);
+        return -EINVAL;
+    }
+
+    if (platform_can_split_snd_device(snd_device,
+                                      &num_devices, new_snd_device) < 0) {
+        new_snd_device[0] = snd_device;
+    }
+
+    for (i = 0; i < num_devices; i++) {
+        acdb_dev_id = acdb_device_table[new_snd_device[i]];
+        if (acdb_dev_id < 0) {
+            ALOGE("%s: Could not find acdb id for device(%d)",
+                  __func__, new_snd_device[i]);
+            return -EINVAL;
+        }
+        ALOGV("%s: sending audio calibration for snd_device(%d) acdb_id(%d)",
+              __func__, new_snd_device[i], acdb_dev_id);
+        if (new_snd_device[i] >= SND_DEVICE_OUT_BEGIN &&
+                new_snd_device[i] < SND_DEVICE_OUT_END)
+            acdb_dev_type = ACDB_DEV_TYPE_OUT;
+        else
+            acdb_dev_type = ACDB_DEV_TYPE_IN;
+
+        if (my_data->acdb_send_audio_cal_v3) {
+            my_data->acdb_send_audio_cal_v3(acdb_dev_id, acdb_dev_type,
+                                            app_type, sample_rate, i);
+        } else if (my_data->acdb_send_audio_cal) {
+            my_data->acdb_send_audio_cal(acdb_dev_id, acdb_dev_type); // this version differs from internal
+        }
+    }
+
+    return 0;
+}
+
+
 int platform_switch_voice_call_device_pre(void *platform)
 {
     struct platform_data *my_data = (struct platform_data *)platform;
@@ -2195,11 +2308,18 @@
                         // since Hearing will be on handset\speaker, use existing device
                         snd_device = SND_DEVICE_OUT_VOICE_TTY_HCO_HANDSET;
                         break;
+                    case TTY_MODE_OFF:
+                        break;
                     default:
                         ALOGE("%s: Invalid TTY mode (%#x)",
                               __func__, adev->voice.tty_mode);
                 }
             }
+            if (snd_device == SND_DEVICE_NONE) {
+                    snd_device = audio_extn_usb_is_capture_supported() ?
+                                 SND_DEVICE_OUT_VOICE_USB_HEADSET :
+                                 SND_DEVICE_OUT_VOICE_USB_HEADPHONES;
+            }
         } else if (devices & AUDIO_DEVICE_OUT_ALL_SCO) {
             if (adev->bt_wb_speech_enabled) {
                 snd_device = SND_DEVICE_OUT_BT_SCO_WB;
@@ -2368,6 +2488,10 @@
             }
         } else if (out_device & AUDIO_DEVICE_OUT_TELEPHONY_TX) {
             snd_device = SND_DEVICE_IN_VOICE_RX;
+        } else if (out_device & AUDIO_DEVICE_OUT_USB_DEVICE) {
+          if (audio_extn_usb_is_capture_supported()) {
+            snd_device = SND_DEVICE_IN_VOICE_USB_HEADSET_MIC;
+          }
         }
     } else if (source == AUDIO_SOURCE_CAMCORDER) {
         if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC ||
@@ -2424,6 +2548,8 @@
             }
         } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
             snd_device = SND_DEVICE_IN_VOICE_REC_HEADSET_MIC;
+        } else if (in_device & AUDIO_DEVICE_IN_USB_DEVICE) {
+            snd_device = SND_DEVICE_IN_VOICE_RECOG_USB_HEADSET_MIC;
         }
     } else if (source == AUDIO_SOURCE_UNPROCESSED) {
         if (in_device & AUDIO_DEVICE_IN_BUILTIN_MIC) {
@@ -2442,6 +2568,8 @@
             }
         } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
             snd_device = SND_DEVICE_IN_UNPROCESSED_HEADSET_MIC;
+        } else if (in_device & AUDIO_DEVICE_IN_USB_DEVICE) {
+            snd_device = SND_DEVICE_IN_UNPROCESSED_USB_HEADSET_MIC;
         }
     } else if (source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
                mode == AUDIO_MODE_IN_COMMUNICATION) {
@@ -2467,6 +2595,8 @@
                     }
                 } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
                     snd_device = SND_DEVICE_IN_HEADSET_MIC_AEC;
+                } else if (in_device & AUDIO_DEVICE_IN_USB_DEVICE) {
+                    snd_device = SND_DEVICE_IN_USB_HEADSET_MIC_AEC;
                 }
                 platform_set_echo_reference(adev, true, out_device);
             } else if (adev->active_input->enable_aec) {
@@ -2487,6 +2617,8 @@
                     }
                } else if (in_device & AUDIO_DEVICE_IN_WIRED_HEADSET) {
                    snd_device = SND_DEVICE_IN_HEADSET_MIC_AEC;
+               } else if (in_device & AUDIO_DEVICE_IN_USB_DEVICE) {
+                   snd_device = SND_DEVICE_IN_USB_HEADSET_MIC_AEC;
                }
                platform_set_echo_reference(adev, true, out_device);
             } else if (adev->active_input->enable_ns) {
@@ -3361,12 +3493,12 @@
     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)
+static void 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;
@@ -3397,6 +3529,27 @@
     return;
 }
 
+static void headset_is_config_supported(unsigned int *bit_width,
+                                        unsigned int *sample_rate,
+                                        unsigned int *channels) {
+    switch (*bit_width) {
+        case 16:
+        case 24:
+            break;
+        default:
+            *bit_width = 16;
+            break;
+    }
+
+    if (*sample_rate > 192000) {
+        *sample_rate = 192000;
+    }
+
+    if (*channels > 2) {
+        *channels = 2;
+    }
+}
+
 static bool platform_check_playback_backend_cfg(struct audio_device* adev,
                                              struct audio_usecase* usecase,
                                              snd_device_t snd_device,
@@ -3406,10 +3559,8 @@
     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) {
@@ -3443,10 +3594,10 @@
          *
          * 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);
+        pick_playback_cfg_for_uc(adev, usecase, snd_device,
+                                 &bit_width,
+                                 &sample_rate,
+                                 &channels);
     }
 
     switch (backend_idx) {
@@ -3456,8 +3607,10 @@
             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:
+            headset_is_config_supported(&bit_width, &sample_rate, &channels);
+            break;
+        case DEFAULT_CODEC_BACKEND:
         default:
             bit_width = platform_get_snd_device_bit_width(snd_device);
             sample_rate = CODEC_BACKEND_DEFAULT_SAMPLE_RATE;
@@ -3465,23 +3618,19 @@
             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) {
+    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_cfg->passthrough_enabled = passthrough_enabled;
+        backend_cfg->passthrough_enabled = false;
         backend_change = true;
         ALOGV("%s:becf: afe: Codec backend needs to be updated. new bit width: %d"
               "new sample rate: %d new channels: %d",
@@ -3566,3 +3715,237 @@
     return false;
 }
 
+static int max_be_dai_names = 0;
+static const struct be_dai_name_struct *be_dai_name_table;
+
+/*
+ * Retrieves the be_dai_name_table from kernel to enable a mapping
+ * between sound device hw interfaces and backend IDs. This allows HAL to
+ * specify the backend a specific calibration is needed for.
+ */
+static int init_be_dai_name_table(struct audio_device *adev)
+{
+    const char *mixer_ctl_name = "Backend DAI Name Table";
+    struct mixer_ctl *ctl;
+    int i, j, ret, size;
+    bool valid_hw_interface;
+
+    ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+    if (!ctl) {
+        ALOGE("%s: Could not get ctl for mixer name %s\n",
+               __func__, mixer_ctl_name);
+        ret = -EINVAL;
+        goto done;
+    }
+
+    mixer_ctl_update(ctl);
+
+    size = mixer_ctl_get_num_values(ctl);
+    if (size <= 0){
+        ALOGE("%s: Failed to get %s size %d\n",
+               __func__, mixer_ctl_name, size);
+        ret = -EFAULT;
+        goto done;
+    }
+
+    posix_memalign((void **)&be_dai_name_table, 32, size);
+    if (be_dai_name_table == NULL) {
+        ALOGE("%s: Failed to allocate memory for %s\n",
+               __func__, mixer_ctl_name);
+        ret = -ENOMEM;
+        goto freeMem;
+    }
+
+    ret = mixer_ctl_get_array(ctl, (void *)be_dai_name_table, size);
+    if (ret) {
+        ALOGE("%s: Failed to get %s, ret %d\n",
+               __func__, mixer_ctl_name, ret);
+        ret = -EFAULT;
+        goto freeMem;
+    }
+
+    if (be_dai_name_table != NULL) {
+        max_be_dai_names = size / sizeof(struct be_dai_name_struct);
+        ALOGV("%s: Successfully got %s, number of be dais is %d\n",
+              __func__, mixer_ctl_name, max_be_dai_names);
+        ret = 0;
+    } else {
+        ALOGE("%s: Failed to get %s\n", __func__, mixer_ctl_name);
+        ret = -EFAULT;
+        goto freeMem;
+    }
+
+    /*
+     * Validate all sound devices have a valid backend set to catch
+     * errors for uncommon sound devices
+     */
+    for (i = 0; i < SND_DEVICE_MAX; i++) {
+        valid_hw_interface = false;
+
+        if (hw_interface_table[i] == NULL) {
+            ALOGW("%s: sound device %s has no hw interface set\n",
+                  __func__, platform_get_snd_device_name(i));
+            continue;
+        }
+
+        for (j = 0; j < max_be_dai_names; j++) {
+            if (strcmp(hw_interface_table[i], be_dai_name_table[j].be_name)
+                == 0) {
+                valid_hw_interface = true;
+                break;
+            }
+        }
+        if (!valid_hw_interface)
+            ALOGD("%s: sound device %s does not have a valid hw interface set "
+                  "(disregard for combo devices) %s\n",
+                  __func__, platform_get_snd_device_name(i),
+                  hw_interface_table[i]);
+    }
+
+    goto done;
+
+freeMem:
+    if (be_dai_name_table) {
+        free((void *)be_dai_name_table);
+        be_dai_name_table = NULL;
+    }
+
+done:
+    return ret;
+}
+
+int platform_get_snd_device_backend_index(snd_device_t device)
+{
+    int i, be_dai_id;
+    const char * hw_interface_name = NULL;
+
+    ALOGV("%s: enter with device %d\n", __func__, device);
+
+    if ((device <= SND_DEVICE_MIN) || (device >= SND_DEVICE_MAX)) {
+        ALOGE("%s: Invalid snd_device = %d",
+              __func__, device);
+        be_dai_id = -EINVAL;
+        goto done;
+    }
+
+    /* Get string value of necessary backend for device */
+    hw_interface_name = hw_interface_table[device];
+    if (hw_interface_name == NULL) {
+        ALOGE("%s: no hw_interface set for device %d\n", __func__, device);
+        be_dai_id = -EINVAL;
+        goto done;
+    }
+
+    /* Check if be dai name table was retrieved successfully */
+    if (be_dai_name_table == NULL) {
+        ALOGE("%s: BE DAI Name Table is not present\n", __func__);
+        be_dai_id = -EFAULT;
+        goto done;
+    }
+
+    /* Get backend ID for device specified */
+    for (i = 0; i < max_be_dai_names; i++) {
+        if (strcmp(hw_interface_name, be_dai_name_table[i].be_name) == 0) {
+            be_dai_id = be_dai_name_table[i].be_id;
+            goto done;
+        }
+    }
+    ALOGE("%s: no interface matching name %s\n", __func__, hw_interface_name);
+    be_dai_id = -EINVAL;
+    goto done;
+
+done:
+    return be_dai_id;
+}
+
+void platform_check_and_update_copp_sample_rate(void* platform, snd_device_t snd_device,
+                                                unsigned int stream_sr, int* sample_rate)
+{
+    struct platform_data* my_data = (struct platform_data *)platform;
+    int backend_idx = platform_get_backend_index(snd_device);
+    int device_sr = my_data->current_backend_cfg[backend_idx].sample_rate;
+    /*
+     *Check if device SR is multiple of 8K or 11.025 Khz
+     *check if the stream SR is multiple of same base, if yes
+     *then have copp SR equal to stream SR, this ensures that
+     *post processing happens at stream SR, else have
+     *copp SR equal to device SR.
+     */
+    if (!(((sample_rate_multiple(device_sr, SAMPLE_RATE_8000)) &&
+           (sample_rate_multiple(stream_sr, SAMPLE_RATE_8000))) ||
+          ((sample_rate_multiple(device_sr, SAMPLE_RATE_11025)) &&
+           (sample_rate_multiple(stream_sr, SAMPLE_RATE_11025))))) {
+        *sample_rate = device_sr;
+    } else
+        *sample_rate = stream_sr;
+
+    ALOGI("sn_device %d device sr %d stream sr %d copp sr %d", snd_device, device_sr, stream_sr
+          , *sample_rate);
+
+}
+
+// called from info parser
+void platform_add_app_type(int bw, const char *uc_type,
+                           int app_type, int max_rate) {
+    struct app_type_entry *ap =
+            (struct app_type_entry *)calloc(1, sizeof(struct app_type_entry));
+
+    if (!ap) {
+        ALOGE("%s failed to allocate mem for app type", __func__);
+        return;
+    }
+
+    ap->uc_type = -1;
+    for (int i=0; i<USECASE_TYPE_MAX; i++) {
+        if (!strcmp(uc_type, usecase_type_index[i].name)) {
+            ap->uc_type = usecase_type_index[i].index;
+            break;
+        }
+    }
+
+    if (ap->uc_type == -1) {
+        free(ap);
+        return;
+    }
+
+    ALOGI("%s bw %d uc %s app_type %d max_rate %d",
+          __func__, bw, uc_type, app_type, max_rate);
+    ap->bit_width = bw;
+    ap->app_type = app_type;
+    ap->max_rate = max_rate;
+    list_add_tail(&app_type_entry_list, &ap->node);
+}
+
+
+int platform_get_default_app_type_v2(void *platform __unused,
+                                     usecase_type_t type,
+                                     int *app_type )
+{
+    if (type == PCM_PLAYBACK)
+        *app_type = DEFAULT_APP_TYPE_RX_PATH;
+    else
+        *app_type = DEFAULT_APP_TYPE_TX_PATH;
+    return 0;
+}
+
+int platform_get_app_type_v2(void *platform, usecase_type_t uc_type,
+                             int bw, int sr __unused,
+                             int *app_type)
+{
+    struct listnode *node;
+    struct app_type_entry *entry;
+    *app_type = -1;
+    list_for_each(node, &app_type_entry_list) {
+        entry = node_to_item(node, struct app_type_entry, node);
+        if (entry->bit_width == bw &&
+            entry->uc_type == uc_type) {
+            *app_type = entry->app_type;
+            break;
+        }
+    }
+
+    if (*app_type == -1) {
+        return platform_get_default_app_type_v2(platform, uc_type, app_type);
+    }
+    return 0;
+}
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index b411e9d..9df8a1d 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -94,6 +94,8 @@
     SND_DEVICE_OUT_USB_HEADSET,
     SND_DEVICE_OUT_USB_HEADPHONES,
     SND_DEVICE_OUT_SPEAKER_AND_USB_HEADSET,
+    SND_DEVICE_OUT_VOICE_USB_HEADPHONES,
+    SND_DEVICE_OUT_VOICE_USB_HEADSET,
     SND_DEVICE_OUT_END,
 
     /*
@@ -161,6 +163,10 @@
     SND_DEVICE_IN_VOICE_RX,
 
     SND_DEVICE_IN_USB_HEADSET_MIC,
+    SND_DEVICE_IN_USB_HEADSET_MIC_AEC,
+    SND_DEVICE_IN_VOICE_USB_HEADSET_MIC,
+    SND_DEVICE_IN_UNPROCESSED_USB_HEADSET_MIC,
+    SND_DEVICE_IN_VOICE_RECOG_USB_HEADSET_MIC,
     SND_DEVICE_IN_THREE_MIC,
     SND_DEVICE_IN_QUAD_MIC,
     SND_DEVICE_IN_CAPTURE_VI_FEEDBACK,
@@ -176,6 +182,8 @@
 };
 #define DEFAULT_OUTPUT_SAMPLING_RATE    48000
 #define OUTPUT_SAMPLING_RATE_44100      44100
+#define DEFAULT_INPUT_SAMPLING_RATE 48000
+
 enum {
     DEFAULT_CODEC_BACKEND,
     SLIMBUS_0_RX = DEFAULT_CODEC_BACKEND,
@@ -196,8 +204,6 @@
 #define DEVICE_NAME_MAX_SIZE   128
 #define HW_INFO_ARRAY_MAX_SIZE 32
 
-#define DEFAULT_OUTPUT_SAMPLING_RATE 48000
-
 #define ALL_SESSION_VSID                0xFFFFFFFF
 #define DEFAULT_MUTE_RAMP_DURATION_MS   20
 #define DEFAULT_VOLUME_RAMP_DURATION_MS 20
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 59ad4b1..c51c492 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -50,6 +50,8 @@
 int platform_set_snd_device_acdb_id(snd_device_t snd_device, unsigned int acdb_id);
 int platform_get_snd_device_acdb_id(snd_device_t snd_device);
 int platform_send_audio_calibration(void *platform, snd_device_t snd_device);
+int platform_send_audio_calibration_v2(void *platform, struct audio_usecase *usecase,
+                                           int app_type, int sample_rate);
 int platform_get_default_app_type_v2(void *platform, enum usecase_type_t type, int *app_type);
 int platform_switch_voice_call_device_pre(void *platform);
 int platform_switch_voice_call_enable_device_config(void *platform,
@@ -105,6 +107,9 @@
 /* From platform_info.c */
 int platform_info_init(const char *filename, void *);
 
+typedef int (*set_parameters_fn)(void *platform, struct str_parms *parms);
+int snd_card_info_init(const char *filename, void *, set_parameters_fn);
+
 int platform_get_usecase_index(const char * usecase);
 int platform_set_usecase_pcm_id(audio_usecase_t usecase, int32_t type, int32_t pcm_id);
 void platform_set_echo_reference(struct audio_device *adev, bool enable, audio_devices_t out_device);
@@ -125,4 +130,11 @@
                    struct audio_usecase *usecase, snd_device_t snd_device);
 
 int platform_snd_card_update(void *platform, enum card_status_t status);
+void platform_check_and_update_copp_sample_rate(void *platform, snd_device_t snd_device,
+     unsigned int stream_sr,int *sample_rate);
+int platform_get_snd_device_backend_index(snd_device_t snd_device);
+bool platform_supports_app_type_cfg();
+int platform_get_app_type_v2(void *platform, enum usecase_type_t type,
+                             int bw, int sr, int *app_type);
+void platform_add_app_type(int bw, const char *uc_type, int app_type, int max_sr);
 #endif // AUDIO_PLATFORM_API_H
diff --git a/hal/platform_info.c b/hal/platform_info.c
index f6b57e3..cd2b5d4 100644
--- a/hal/platform_info.c
+++ b/hal/platform_info.c
@@ -34,6 +34,7 @@
     CONFIG_PARAMS,
     OPERATOR_SPECIFIC,
     GAIN_LEVEL_MAPPING,
+    APP_TYPE,
 } section_t;
 
 typedef void (* section_process_fn)(const XML_Char **attr);
@@ -45,6 +46,7 @@
 static void process_root(const XML_Char **attr);
 static void process_operator_specific(const XML_Char **attr);
 static void process_gain_db_to_level_map(const XML_Char **attr);
+static void process_app_type(const XML_Char **attr);
 
 static section_process_fn section_table[] = {
     [ROOT] = process_root,
@@ -54,16 +56,20 @@
     [CONFIG_PARAMS] = process_config_params,
     [OPERATOR_SPECIFIC] = process_operator_specific,
     [GAIN_LEVEL_MAPPING] = process_gain_db_to_level_map,
+    [APP_TYPE] = process_app_type,
 };
 
+static set_parameters_fn set_parameters = &platform_set_parameters;
+
 static section_t section;
 
 struct platform_info {
+    bool              do_full_parse;
     void             *platform;
     struct str_parms *kvpairs;
 };
 
-static struct platform_info my_data;
+static struct platform_info my_data = {true, NULL, NULL};
 
 /*
  * <audio_platform_info>
@@ -302,7 +308,34 @@
     }
 
     str_parms_add_str(my_data.kvpairs, (char*)attr[1], (char*)attr[3]);
-    platform_set_parameters(my_data.platform, my_data.kvpairs);
+    set_parameters(my_data.platform, my_data.kvpairs);
+done:
+    return;
+}
+
+static void process_app_type(const XML_Char **attr)
+{
+    if (strcmp(attr[0], "uc_type")) {
+        ALOGE("%s: uc_type not found", __func__);
+        goto done;
+    }
+
+    if (strcmp(attr[2], "bit_width")) {
+        ALOGE("%s: bit_width not found", __func__);
+        goto done;
+    }
+
+    if (strcmp(attr[4], "id")) {
+        ALOGE("%s: id not found", __func__);
+        goto done;
+    }
+
+    if (strcmp(attr[6], "max_rate")) {
+        ALOGE("%s: max rate not found", __func__);
+        goto done;
+    }
+
+    platform_add_app_type(atoi(attr[3]), attr[1], atoi(attr[5]), atoi(attr[7]));
 done:
     return;
 }
@@ -314,51 +347,76 @@
     const XML_Char              *attr_value = NULL;
     unsigned int                i;
 
-    if (strcmp(tag_name, "acdb_ids") == 0) {
-        section = ACDB;
-    } else if (strcmp(tag_name, "pcm_ids") == 0) {
-        section = PCM_ID;
-    } else if (strcmp(tag_name, "backend_names") == 0) {
-        section = BACKEND_NAME;
-    } else if (strcmp(tag_name, "config_params") == 0) {
-        section = CONFIG_PARAMS;
-    } else if (strcmp(tag_name, "operator_specific") == 0) {
-        section = OPERATOR_SPECIFIC;
-    } else if (strcmp(tag_name, "gain_db_to_level_mapping") == 0) {
-        section = GAIN_LEVEL_MAPPING;
-    } else if (strcmp(tag_name, "device") == 0) {
-        if ((section != ACDB) && (section != BACKEND_NAME) && (section != OPERATOR_SPECIFIC)) {
-            ALOGE("device tag only supported for acdb/backend names");
-            return;
-        }
 
-        /* call into process function for the current section */
-        section_process_fn fn = section_table[section];
-        fn(attr);
-    } else if (strcmp(tag_name, "usecase") == 0) {
-        if (section != PCM_ID) {
-            ALOGE("usecase tag only supported with PCM_ID section");
-            return;
-        }
+    if (my_data.do_full_parse) {
+        if (strcmp(tag_name, "acdb_ids") == 0) {
+            section = ACDB;
+        } else if (strcmp(tag_name, "pcm_ids") == 0) {
+            section = PCM_ID;
+        } else if (strcmp(tag_name, "backend_names") == 0) {
+            section = BACKEND_NAME;
+        } else if (strcmp(tag_name, "config_params") == 0) {
+            section = CONFIG_PARAMS;
+        } else if (strcmp(tag_name, "operator_specific") == 0) {
+            section = OPERATOR_SPECIFIC;
+        } else if (strcmp(tag_name, "gain_db_to_level_mapping") == 0) {
+            section = GAIN_LEVEL_MAPPING;
+        } else if (strcmp(tag_name, "app_types") == 0) {
+            section = APP_TYPE;
+        } else if (strcmp(tag_name, "device") == 0) {
+            if ((section != ACDB) && (section != BACKEND_NAME) && (section != OPERATOR_SPECIFIC)) {
+                ALOGE("device tag only supported for acdb/backend names");
+                return;
+            }
 
-        section_process_fn fn = section_table[PCM_ID];
-        fn(attr);
-    } else if (strcmp(tag_name, "param") == 0) {
-        if (section != CONFIG_PARAMS) {
-            ALOGE("param tag only supported with CONFIG_PARAMS section");
-            return;
-        }
+            /* call into process function for the current section */
+            section_process_fn fn = section_table[section];
+            fn(attr);
+        } else if (strcmp(tag_name, "usecase") == 0) {
+            if (section != PCM_ID) {
+                ALOGE("usecase tag only supported with PCM_ID section");
+                return;
+            }
 
-        section_process_fn fn = section_table[section];
-        fn(attr);
-    } else if (strcmp(tag_name, "gain_level_map") == 0) {
-        if (section != GAIN_LEVEL_MAPPING) {
-            ALOGE("usecase tag only supported with GAIN_LEVEL_MAPPING section");
-            return;
-        }
+            section_process_fn fn = section_table[PCM_ID];
+            fn(attr);
+        } else if (strcmp(tag_name, "param") == 0) {
+            if (section != CONFIG_PARAMS) {
+                ALOGE("param tag only supported with CONFIG_PARAMS section");
+                return;
+            }
 
-        section_process_fn fn = section_table[GAIN_LEVEL_MAPPING];
-        fn(attr);
+            section_process_fn fn = section_table[section];
+            fn(attr);
+        } else if (strcmp(tag_name, "gain_level_map") == 0) {
+            if (section != GAIN_LEVEL_MAPPING) {
+                ALOGE("usecase tag only supported with GAIN_LEVEL_MAPPING section");
+                return;
+            }
+
+            section_process_fn fn = section_table[GAIN_LEVEL_MAPPING];
+            fn(attr);
+        } else if (!strcmp(tag_name, "app")) {
+            if (section != APP_TYPE) {
+                ALOGE("app tag only valid in section APP_TYPE");
+                return;
+            }
+
+            section_process_fn fn = section_table[APP_TYPE];
+            fn(attr);
+        }
+    } else {
+        if(strcmp(tag_name, "config_params") == 0) {
+            section = CONFIG_PARAMS;
+        } else if (strcmp(tag_name, "param") == 0) {
+            if (section != CONFIG_PARAMS) {
+                ALOGE("param tag only supported with CONFIG_PARAMS section");
+                return;
+            }
+
+            section_process_fn fn = section_table[section];
+            fn(attr);
+        }
     }
 
     return;
@@ -378,9 +436,18 @@
         section = ROOT;
     } else if (strcmp(tag_name, "gain_db_to_level_mapping") == 0) {
         section = ROOT;
+    } else if (strcmp(tag_name, "app_types") == 0) {
+        section = ROOT;
     }
 }
 
+int snd_card_info_init(const char *filename, void *platform, set_parameters_fn fn)
+{
+    set_parameters = fn;
+    my_data.do_full_parse = false;
+    return platform_info_init(filename, platform);
+}
+
 int platform_info_init(const char *filename, void *platform)
 {
     XML_Parser      parser;
@@ -448,6 +515,9 @@
             break;
     }
 
+    set_parameters = &platform_set_parameters;
+    my_data.do_full_parse = true;
+
 err_free_parser:
     XML_ParserFree(parser);
 err_close_file:
diff --git a/post_proc/Android.mk b/post_proc/Android.mk
index eb59ddb..493f2cc 100644
--- a/post_proc/Android.mk
+++ b/post_proc/Android.mk
@@ -1,4 +1,4 @@
-ifneq ($(filter msm8974 msm8226 msm8084 msm8992 msm8994 msm8996 msm8909,$(TARGET_BOARD_PLATFORM)),)
+ifneq ($(filter msm8974 msm8226 msm8084 msm8992 msm8994 msm8996 msm8909 msm8998,$(TARGET_BOARD_PLATFORM)),)
 
 LOCAL_PATH:= $(call my-dir)
 
@@ -35,7 +35,7 @@
 
 ################################################################################
 
-ifneq ($(filter msm8992 msm8994 msm8996 msm8909,$(TARGET_BOARD_PLATFORM)),)
+ifneq ($(filter msm8992 msm8994 msm8996 msm8909 msm8998,$(TARGET_BOARD_PLATFORM)),)
 
 include $(CLEAR_VARS)