audio: support hifi audio record with USB
Add support to record hifi audio when USB is connected
Bug: 37304195
Test: test playback and capture with and without USB headset
Change-Id: I4f4142aba495e9625b17ba007280f76fbc66a641
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 85a5881..100741f 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
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_hw.c b/hal/audio_hw.c
index 3318cc1..2f5e6d1 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,
+ uint32_t *supported_sample_rates,
+ uint32_t max_rates)
{
- 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,
+ 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)
@@ -2138,29 +2188,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 +2214,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 +2240,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 +2281,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 +3022,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 +3432,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 +3457,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 +3486,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);
@@ -3901,6 +3999,8 @@
int ret = 0, buffer_size, frame_size;
int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
bool is_low_latency = false;
+ bool is_usb_dev = audio_is_usb_in_device(devices);
+ bool may_use_hifi_record = !(flags & (AUDIO_INPUT_FLAG_RAW|AUDIO_INPUT_FLAG_MMAP_NOIRQ));
ALOGV("%s: enter", __func__);
*stream_in = NULL;
@@ -3940,9 +4040,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 +4108,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 +4135,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;
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/msm8974/platform.c b/hal/msm8974/platform.c
index b9812b1..66719bb 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)},
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.