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();