audio: Dynamic USB profile changes

Add support for hifi playback and record usecase

CRs-Fixed: 2106614
Change-Id: Ic0d5c8907e9951e8205131060071101ca16a455b
diff --git a/hal/audio_extn/usb.c b/hal/audio_extn/usb.c
index 7b0309b..60216b1 100644
--- a/hal/audio_extn/usb.c
+++ b/hal/audio_extn/usb.c
@@ -53,10 +53,14 @@
 #define SAMPLE_RATE_11025         11025
 // Supported sample rates for USB
 static uint32_t supported_sample_rates[] =
-    {8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000, 352800, 384000};
+    {384000, 352800, 192000, 176400, 96000, 88200, 64000, 48000, 44100, 32000, 22050, 16000, 11025, 8000};
+static uint32_t supported_sample_rates_mask[2];
 
 #define  MAX_SAMPLE_RATE_SIZE  sizeof(supported_sample_rates)/sizeof(supported_sample_rates[0])
 
+#define _MAX(x, y) (((x) >= (y)) ? (x) : (y))
+#define _MIN(x, y) (((x) <= (y)) ? (x) : (y))
+
 enum usb_usecase_type{
     USB_PLAYBACK = 0,
     USB_CAPTURE,
@@ -246,7 +250,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;
@@ -277,6 +281,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]);
@@ -291,6 +296,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);
@@ -455,7 +461,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) {
@@ -551,13 +557,24 @@
     return;
 }
 
-static bool usb_valid_device(int device)
+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)
 {
-    bool is_usb_device = false;
-    if ((device & AUDIO_DEVICE_OUT_USB_DEVICE) ||
-        (device & AUDIO_DEVICE_IN_USB_DEVICE))
-        is_usb_device = true;
-    return is_usb_device;
+    return usb_output_device(device) ||
+           usb_input_device(device);
 }
 
 static void usb_print_active_device(void){
@@ -852,7 +869,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,
@@ -898,8 +915,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))){
             is_usb_supported = usb_audio_backend_apply_policy(
                                            &card_info->usb_device_conf_list,
                                            bit_width,
@@ -914,6 +931,70 @@
     return is_usb_supported;
 }
 
+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->channels);
+            }
+    }
+
+    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_get_sup_sample_rates(bool is_playback,
+                                        uint32_t *sample_rates,
+                                        uint32_t sample_rate_size)
+{
+    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) {
@@ -968,18 +1049,18 @@
         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_pb_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_cap_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;
@@ -1034,7 +1115,12 @@
             free(node_to_item(node_i, struct usb_card_config, list));
         }
     }
-    usbmod->is_capture_supported = false;
+    if (audio_is_usb_in_device(device)) { // XXX not sure if we need to check for card
+        usbmod->is_capture_supported = false;
+        supported_sample_rates_mask[USB_CAPTURE] = 0;
+    } else
+        supported_sample_rates_mask[USB_PLAYBACK] = 0;
+
 exit:
     if (usb_audio_debug_enable)
         usb_print_active_device();