release-request-d6bf2db5-83c3-41cb-ba89-644c366c2525-for-git_oc-mr1-release-4070602 snap-temp-L56000000070867102

Change-Id: I50b192e7290a481cf164d29780dde67db49d2f9c
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 85a5881..600c179 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -79,8 +79,8 @@
 #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()                              (0)
-#define audio_extn_usb_get_max_bit_width()                             (0)
+#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);
@@ -95,9 +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();
-int audio_extn_usb_get_max_bit_width();
-int audio_extn_usb_sup_sample_rates(int type, uint32_t *sr, uint32_t l);
+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
 
 
@@ -187,7 +187,7 @@
 #endif
 
 bool audio_extn_utils_resolve_config_file(char[]);
-void audio_extn_utils_get_platform_info(const char* snd_card_name,
-                                        char* platform_info_file);
+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 a1af141..4e4c70d 100644
--- a/hal/audio_extn/usb.c
+++ b/hal/audio_extn/usb.c
@@ -290,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) ?
@@ -298,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",
@@ -518,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){
@@ -821,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,
@@ -866,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,
@@ -884,7 +901,7 @@
 #define _MAX(x, y) (((x) >= (y)) ? (x) : (y))
 #define _MIN(x, y) (((x) <= (y)) ? (x) : (y))
 
-int audio_extn_usb_get_max_channels()
+int audio_extn_usb_get_max_channels(bool is_playback)
 {
     struct listnode *node_i, *node_j;
     struct usb_device_config *dev_info;
@@ -892,6 +909,11 @@
     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);
@@ -901,7 +923,7 @@
     return max_ch;
 }
 
-int audio_extn_usb_get_max_bit_width()
+int audio_extn_usb_get_max_bit_width(bool is_playback)
 {
     struct listnode *node_i, *node_j;
     struct usb_device_config *dev_info;
@@ -909,6 +931,11 @@
     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);
@@ -918,7 +945,7 @@
     return max_bw;
 }
 
-int audio_extn_usb_sup_sample_rates(int type,
+int audio_extn_usb_sup_sample_rates(bool is_playback,
                                     uint32_t *sample_rates,
                                     uint32_t sample_rate_size)
 {
@@ -926,8 +953,7 @@
     struct usb_device_config *dev_info;
     struct usb_card_config *card_info;
 
-    if (type != USB_PLAYBACK && type != USB_CAPTURE)
-        return -1;
+    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];
@@ -997,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)
@@ -1060,6 +1088,9 @@
                 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));
         }
     }
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index e41af96..eb0f9f6 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -324,14 +324,14 @@
 }
 
 /* platform_info_file should be size 'MIXER_PATH_MAX_LENGTH' */
-void audio_extn_utils_get_platform_info(const char* snd_card_name, char* platform_info_file)
+int audio_extn_utils_get_platform_info(const char* snd_card_name, char* platform_info_file)
 {
     if (NULL == snd_card_name) {
-        return;
+        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();
 
@@ -347,9 +347,11 @@
         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);
-            audio_extn_utils_resolve_config_file(platform_info_file);
+            ret = audio_extn_utils_resolve_config_file(platform_info_file) ? 0 : -1;
         }
     }
+
+    return ret;
 }
 
 int audio_extn_utils_get_snd_card_num()
@@ -399,10 +401,17 @@
         snd_card_name = mixer_get_name(mixer);
         hw_info = hw_info_init(snd_card_name);
 
-        audio_extn_utils_get_platform_info(snd_card_name, platform_info_file);
+        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*/
-        snd_card_info_init(platform_info_file, my_data, &acdb_set_parameters);
+        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
@@ -419,17 +428,18 @@
                         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(mixer);
-            mixer = NULL;
-            hw_info_deinit(hw_info);
-            hw_info = NULL;
-            continue;
+            goto cleanup;
         }
 
-        ALOGI("%s: found sound card %s, primary sound card expeted is %s",
+        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:
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 3318cc1..e689b28 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -247,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",
@@ -279,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);
@@ -964,48 +967,95 @@
     return ret;
 }
 
-static int read_usb_sup_sample_rates(struct stream_out *out)
+static ssize_t read_usb_sup_sample_rates(bool is_playback __unused,
+                                         uint32_t *supported_sample_rates __unused,
+                                         uint32_t max_rates __unused)
 {
-    uint32_t *sr = out->supported_sample_rates;
-    size_t count = audio_extn_usb_sup_sample_rates(0 /*playback*/,
-                                                   sr,
-                                                   MAX_SUPPORTED_SAMPLE_RATES);
+    ssize_t count = audio_extn_usb_sup_sample_rates(is_playback,
+                                                    supported_sample_rates,
+                                                    max_rates);
 #if !LOG_NDEBUG
-
-    for (size_t i=0; i<count; i++) {
-        ALOGV("%s %d", __func__, out->supported_sample_rates[i]);
+    for (ssize_t i=0; i<count; i++) {
+        ALOGV("%s %s %d", __func__, is_playback ? "P" : "C",
+              supported_sample_rates[i]);
     }
 #endif
-    return count > 0 ? 0 : -1;
+    return count;
 }
 
-static int read_usb_sup_channel_masks(struct stream_out *out)
+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();
-    out->supported_channel_masks[0] =
-            channels < 3 ? audio_channel_out_mask_from_count(channels) :
-                           audio_channel_mask_for_index_assignment_from_count(channels);
-    return 0;
+    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(struct stream_out *out)
+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();
+    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?
-            out->supported_formats[0] = AUDIO_FORMAT_PCM_24_BIT_PACKED;
+            supported_formats[0] = AUDIO_FORMAT_PCM_24_BIT_PACKED;
             break;
         case 32:
-            out->supported_formats[0] = AUDIO_FORMAT_PCM_32_BIT;
+            supported_formats[0] = AUDIO_FORMAT_PCM_32_BIT;
             break;
         case 16:
         default :
-            out->supported_formats[0] = AUDIO_FORMAT_PCM_16_BIT;
+            supported_formats[0] = AUDIO_FORMAT_PCM_16_BIT;
             break;
     }
+    ALOGV("%s: %s supported format %d", __func__,
+          is_playback ? "P" : "C", bitwidth);
+    return 1;
+}
 
-    return 0;
+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)
@@ -1748,7 +1798,7 @@
             goto error_open;
         }
     } else {
-        unsigned int flags = PCM_OUT;
+        unsigned int flags = PCM_OUT | PCM_MONOTONIC;
         unsigned int pcm_open_retry_count = 0;
 
         if (out->usecase == USECASE_AUDIO_PLAYBACK_AFE_PROXY) {
@@ -1756,8 +1806,7 @@
             pcm_open_retry_count = PROXY_OPEN_RETRY_COUNT;
         } else if (out->realtime) {
             flags |= PCM_MMAP | PCM_NOIRQ;
-        } else
-            flags |= PCM_MONOTONIC;
+        }
 
         while (1) {
             out->pcm = pcm_open(adev->snd_card, out->pcm_device_id,
@@ -1814,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;
     }
@@ -1835,6 +1886,7 @@
     case 32000:
     case 44100:
     case 48000:
+    case 96000:
         break;
     default:
         ALOGE("%s: unsupported (%d) samplerate passed ", __func__, sample_rate);
@@ -2138,29 +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();
-    bool replied = false;
-    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;
                 }
@@ -2168,13 +2216,21 @@
             i++;
         }
         str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value);
-        replied = true;
     }
+    return ret >= 0;
+}
 
-    ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value, sizeof(value));
-    if (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 (out->supported_formats[0]) {
+        switch (supported_formats[0]) {
             case AUDIO_FORMAT_PCM_16_BIT:
                 strcat(value, "AUDIO_FORMAT_PCM_16_BIT");
                 break;
@@ -2186,24 +2242,31 @@
                 break;
             default:
                 ALOGE("%s: unsupported format %#x", __func__,
-                      out->supported_formats[0]);
+                      supported_formats[0]);
                 break;
         }
         str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value);
-        replied = true;
     }
+    return ret >= 0;
+}
 
-    ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES,
-                            value, sizeof(value));
-    if (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 (out->supported_sample_rates[i]) {
+        while (supported_sample_rates[i]) {
             int avail = sizeof(value) - cursor;
             ret = snprintf(value + cursor, avail, "%s%d",
                            cursor > 0 ? "|" : "",
-                           out->supported_sample_rates[i]);
+                           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
@@ -2220,9 +2283,25 @@
         }
         str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES,
                           value);
-        replied = true;
     }
+    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 {
@@ -2945,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)
@@ -3334,7 +3434,10 @@
     struct audio_device *adev = (struct audio_device *)dev;
     struct stream_out *out;
     int i, ret;
-    const uint32_t direct_dev = (AUDIO_DEVICE_OUT_HDMI|AUDIO_DEVICE_OUT_USB_DEVICE);
+    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);
@@ -3356,18 +3459,27 @@
     /* Init use case and pcm_config */
     if (audio_is_linear_pcm(out->format) &&
         (out->flags == AUDIO_OUTPUT_FLAG_NONE ||
-         out->flags == AUDIO_OUTPUT_FLAG_DIRECT) &&
-        (out->devices & direct_dev)) {
-
-        bool hdmi = (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL);
-
+         out->flags == AUDIO_OUTPUT_FLAG_DIRECT) && direct_dev) {
         pthread_mutex_lock(&adev->lock);
-        if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+        if (is_hdmi) {
             ret = read_hdmi_channel_masks(out);
-        } else if (out->devices & AUDIO_DEVICE_OUT_USB_DEVICE) {
-            ret = read_usb_sup_formats(out) ||
-                  read_usb_sup_channel_masks(out) ||
-                  read_usb_sup_sample_rates(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;
@@ -3376,24 +3488,12 @@
         if (ret != 0)
             goto error_open;
 
-        if (config->sample_rate == 0) {
-            out->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
-        } else {
-            out->sample_rate = config->sample_rate;
-        }
-        if (config->channel_mask == 0) {
-            out->channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
-        } else {
-            out->channel_mask = config->channel_mask;
-        }
-        if (config->format == AUDIO_FORMAT_DEFAULT) {
-            out->format = AUDIO_FORMAT_PCM_16_BIT;
-        } else {
-            out->format = config->format;
-        }
+        out->channel_mask = config->channel_mask;
+        out->sample_rate = config->sample_rate;
+        out->format = config->format;
         out->usecase = USECASE_AUDIO_PLAYBACK_HIFI;
         // does this change?
-        out->config = hdmi ? pcm_config_hdmi_multi : pcm_config_hifi;
+        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);
@@ -3887,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,
@@ -3901,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));
@@ -3940,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 ||
@@ -3993,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 &&
@@ -4008,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;
@@ -4019,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;
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index e410d64..b1e5e45 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -96,6 +96,7 @@
     USECASE_AUDIO_RECORD,
     USECASE_AUDIO_RECORD_LOW_LATENCY,
     USECASE_AUDIO_RECORD_MMAP,
+    USECASE_AUDIO_RECORD_HIFI,
 
     /* Voice extension usecases
      *
@@ -246,6 +247,14 @@
     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 {
diff --git a/hal/msm8916/platform.h b/hal/msm8916/platform.h
index 6e1fb88..07dc1af 100644
--- a/hal/msm8916/platform.h
+++ b/hal/msm8916/platform.h
@@ -157,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.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 b9812b1..02512ea 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -165,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},
@@ -553,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)},
@@ -1027,6 +1031,8 @@
     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");
@@ -1034,6 +1040,18 @@
     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;
 }
diff --git a/hal/msm8974/platform.h b/hal/msm8974/platform.h
index 61da332..9df8a1d 100644
--- a/hal/msm8974/platform.h
+++ b/hal/msm8974/platform.h
@@ -182,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,
@@ -202,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_info.c b/hal/platform_info.c
index c63f244..cd2b5d4 100644
--- a/hal/platform_info.c
+++ b/hal/platform_info.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014-2017 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.