audio: support custom acdb for external device
add the specific external device setting in audio_platform_info.xml
For example:
<external_specific_dev>
<ext_device name="SND_DEVICE_OUT_USB_HEADSET" usbid="18d1:5034" acdb_id="10" />
</external_specific_dev>
Bug: 117336751
Test: manual test ok
Change-Id: Ie9abcadd9bcd6d06c5d8f0a9807c3935ee4a1d35
Signed-off-by: Carter Hsu <carterhsu@google.com>
Signed-off-by: Robert Lee <lerobert@google.com>
(cherry picked from commit 017c63ae09841070e587d0f9f5c396efcb07e46d)
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index 24ed4c5..1688b9d 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -1105,6 +1105,7 @@
bool usb_is_tunnel_supported();
bool usb_alive(int card);
bool usb_connected(struct str_parms *parms);
+char *usb_usbid(void);
unsigned long usb_find_service_interval(bool min, bool playback);
int usb_altset_for_service_interval(bool is_playback,
unsigned long service_interval,
@@ -1265,6 +1266,15 @@
return ret_val;
}
+char *audio_extn_usb_usbid(void)
+{
+ char *ret_val = NULL;
+ if (is_usb_offload_enabled)
+ ret_val = usb_usbid();
+
+ return ret_val;
+}
+
unsigned long audio_extn_usb_find_service_interval(bool min, bool playback)
{
unsigned long ret_val = 0;
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index e1e3ca0..60b2610 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -283,6 +283,7 @@
uint32_t *bit_width,
uint32_t *sample_rate,
uint32_t *channel_count);
+char *audio_extn_usb_usbid(void);
int audio_extn_usb_set_service_interval(bool playback,
unsigned long service_interval,
bool *reconfig);
diff --git a/hal/audio_extn/usb.c b/hal/audio_extn/usb.c
index 9981ef0..e6859fe 100644
--- a/hal/audio_extn/usb.c
+++ b/hal/audio_extn/usb.c
@@ -55,6 +55,7 @@
#define SAMPLE_RATE_11025 11025
#define SAMPLE_RATE_192000 192000
// Supported sample rates for USB
+#define USBID_SIZE 16
static uint32_t supported_sample_rates[] =
{384000, 352800, 192000, 176400, 96000, 88200, 64000, 48000, 44100, 32000, 22050, 16000, 11025, 8000};
static uint32_t supported_sample_rates_mask[2];
@@ -97,6 +98,7 @@
int usb_sidetone_vol_min;
int usb_sidetone_vol_max;
int endian;
+ char usbid[USBID_SIZE];
};
struct usb_module {
@@ -620,6 +622,48 @@
return ret;
}
+static int usb_get_usbid(struct usb_card_config *usb_card_info,
+ int card)
+{
+ int32_t fd=-1;
+ char path[128];
+ int ret = 0;
+
+ memset(usb_card_info->usbid, 0, sizeof(usb_card_info->usbid));
+
+ ret = snprintf(path, sizeof(path), "/proc/asound/card%u/usbid",
+ card);
+
+ if (ret < 0) {
+ ALOGE("%s: failed on snprintf (%d) to path %s\n",
+ __func__, ret, path);
+ goto done;
+ }
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0) {
+ ALOGE("%s: error failed to open file %s error: %d\n",
+ __func__, path, errno);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (read(fd, usb_card_info->usbid, USBID_SIZE - 1) < 0) {
+ ALOGE("file read error\n");
+ ret = -EINVAL;
+ usb_card_info->usbid[0] = '\0';
+ goto done;
+ }
+
+ strtok(usb_card_info->usbid, "\n");
+
+done:
+ if (fd >= 0)
+ close(fd);
+
+ return ret;
+}
+
static int usb_get_device_cap_config(struct usb_card_config *usb_card_info,
int card)
{
@@ -1164,6 +1208,10 @@
}
list_init(&usb_card_info->usb_device_conf_list);
if (usb_output_device(device)) {
+ if (usb_get_usbid(usb_card_info, card) < 0) {
+ ALOGE("parse card %d usbid fail", card);
+ }
+
if (!usb_get_device_pb_config(usb_card_info, card)){
usb_card_info->usb_card = card;
usb_card_info->usb_device_type = device;
@@ -1172,6 +1220,10 @@
goto exit;
}
} else if (usb_input_device(device)) {
+ if (usb_get_usbid(usb_card_info, card) < 0) {
+ ALOGE("parse card %d usbid fail", card);
+ }
+
if (!usb_get_device_cap_config(usb_card_info, card)) {
usb_card_info->usb_card = card;
usb_card_info->usb_device_type = device;
@@ -1485,6 +1537,22 @@
return usb_connected;
}
+char *usb_usbid()
+{
+ struct usb_card_config *card_info;
+
+ if (usbmod == NULL)
+ return NULL;
+
+ if (list_empty(&usbmod->usb_card_conf_list))
+ return NULL;
+
+ card_info = node_to_item(list_head(&usbmod->usb_card_conf_list),\
+ struct usb_card_config, list);
+
+ return strdup(card_info->usbid);
+}
+
void usb_init(void *adev)
{
if (usbmod == NULL) {
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 7b15f53..1cb3c1d 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -3154,6 +3154,13 @@
return ret;
}
+void platform_add_external_specific_device(snd_device_t snd_device __unused,
+ const char *name __unused,
+ unsigned int acdb_id __unused)
+{
+ return;
+}
+
int platform_get_snd_device_index(char *device_name)
{
return find_index(snd_device_name_index, SND_DEVICE_MAX, device_name);
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index f21602d..416c70b 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -454,6 +454,13 @@
return -ENOSYS;
}
+void platform_add_external_specific_device(snd_device_t snd_device __unused,
+ const char *name __unused,
+ unsigned int acdb_id __unused)
+{
+ return;
+}
+
int platform_set_snd_device_bit_width(snd_device_t snd_device __unused,
unsigned int bit_width __unused)
{
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index efbd0ae..fceded3 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -235,6 +235,12 @@
int acdb_id;
};
+struct external_specific_device {
+ struct listnode list;
+ char *usbid;
+ int acdb_id;
+};
+
static struct listnode operator_info_list;
static struct listnode *operator_specific_device_table[SND_DEVICE_MAX];
@@ -261,6 +267,8 @@
size_t mic_count;
};
+static struct listnode *external_specific_device_table[SND_DEVICE_MAX];
+
struct platform_data {
struct audio_device *adev;
bool fluence_in_spkr_mode;
@@ -1401,6 +1409,27 @@
static pthread_once_t check_op_once_ctl = PTHREAD_ONCE_INIT;
static bool is_tmus = false;
+static bool is_usb_snd_dev(snd_device_t snd_device)
+{
+ if (snd_device < SND_DEVICE_IN_BEGIN) {
+ if (snd_device == SND_DEVICE_OUT_USB_HEADSET ||\
+ snd_device == SND_DEVICE_OUT_USB_HEADPHONES ||\
+ snd_device == SND_DEVICE_OUT_VOICE_USB_HEADPHONES ||\
+ snd_device == SND_DEVICE_OUT_VOICE_USB_HEADSET ||\
+ snd_device == SND_DEVICE_OUT_VOICE_TTY_FULL_USB ||\
+ snd_device == SND_DEVICE_OUT_VOICE_TTY_VCO_USB)
+ return true;
+ } else {
+ if (snd_device == SND_DEVICE_IN_USB_HEADSET_MIC ||\
+ snd_device == SND_DEVICE_IN_USB_HEADSET_MIC_AEC ||\
+ snd_device == SND_DEVICE_IN_VOICE_USB_HEADSET_MIC ||\
+ snd_device == SND_DEVICE_IN_UNPROCESSED_USB_HEADSET_MIC ||\
+ snd_device == SND_DEVICE_IN_VOICE_RECOG_USB_HEADSET_MIC)
+ return true;
+ }
+ return false;
+}
+
static void check_operator()
{
char value[PROPERTY_VALUE_MAX];
@@ -1489,6 +1518,30 @@
return ret;
}
+static int get_external_specific_device_acdb_id(snd_device_t snd_device)
+{
+ struct external_specific_device *ext_dev;
+ int ret = acdb_device_table[snd_device];
+ char *usbid = NULL;
+ struct listnode *node;
+
+ if (is_usb_snd_dev(snd_device))
+ usbid = audio_extn_usb_usbid();
+
+ if (usbid) {
+ list_for_each(node, external_specific_device_table[snd_device]) {
+ ext_dev = node_to_item(node, struct external_specific_device, list);
+ if (ext_dev->usbid && !strcmp(usbid, ext_dev->usbid)) {
+ ret = ext_dev->acdb_id;
+ break;
+ }
+ }
+
+ free(usbid);
+ }
+ return ret;
+}
+
static const char *get_operator_specific_device_mixer_path(snd_device_t snd_device)
{
struct operator_specific_device *device;
@@ -1906,6 +1959,7 @@
backend_tag_table[dev] = NULL;
hw_interface_table[dev] = NULL;
operator_specific_device_table[dev] = NULL;
+ external_specific_device_table[dev] = NULL;
}
for (dev = 0; dev < SND_DEVICE_MAX; dev++) {
backend_bit_width_table[dev] = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
@@ -3594,6 +3648,7 @@
struct platform_data *my_data = (struct platform_data *)platform;
struct operator_info *info_item;
struct operator_specific_device *device_item;
+ struct external_specific_device *ext_dev;
struct app_type_entry *ap;
struct listnode *node;
@@ -3647,6 +3702,17 @@
free(operator_specific_device_table[dev]);
operator_specific_device_table[dev] = NULL;
}
+
+ if (external_specific_device_table[dev]) {
+ while (!list_empty(external_specific_device_table[dev])) {
+ node = list_head(external_specific_device_table[dev]);
+ list_remove(node);
+ ext_dev = node_to_item(node, struct external_specific_device, list);
+ free(ext_dev->usbid);
+ free(ext_dev);
+ }
+ free(external_specific_device_table[dev]);
+ }
}
while (!list_empty(&operator_info_list)) {
@@ -4029,6 +4095,29 @@
return ret;
}
+void platform_add_external_specific_device(snd_device_t snd_device,
+ const char *usbid,
+ unsigned int acdb_id)
+{
+ struct external_specific_device *device;
+
+ if (external_specific_device_table[snd_device] == NULL) {
+ external_specific_device_table[snd_device] =
+ (struct listnode *)calloc(1, sizeof(struct listnode));
+ list_init(external_specific_device_table[snd_device]);
+ }
+
+ device = (struct external_specific_device *)calloc(1, sizeof(struct external_specific_device));
+
+ device->usbid = strdup(usbid);
+ device->acdb_id = acdb_id;
+
+ list_add_tail(external_specific_device_table[snd_device], &device->list);
+
+ ALOGD("%s: device[%s] usbid[%s] -> acdb_id[%d]", __func__,
+ platform_get_snd_device_name(snd_device), usbid, acdb_id);
+}
+
int platform_set_snd_device_acdb_id(snd_device_t snd_device, unsigned int acdb_id)
{
int ret = 0;
@@ -4144,6 +4233,8 @@
if (operator_specific_device_table[snd_device] != NULL)
return get_operator_specific_device_acdb_id(snd_device);
+ else if (external_specific_device_table[snd_device] != NULL)
+ return get_external_specific_device_acdb_id(snd_device);
else
return acdb_device_table[snd_device];
}
diff --git a/hal/platform_api.h b/hal/platform_api.h
index f4acf1f..f9e5f2a 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -185,6 +185,9 @@
const char *operator,
const char *mixer_path,
unsigned int acdb_id);
+void platform_add_external_specific_device(snd_device_t snd_device,
+ const char *name,
+ unsigned int acdb_id);
void platform_get_parameters(void *platform, struct str_parms *query,
struct str_parms *reply);
int platform_set_parameters(void *platform, struct str_parms *parms);
diff --git a/hal/platform_info.c b/hal/platform_info.c
index da0223e..05ee9cd 100644
--- a/hal/platform_info.c
+++ b/hal/platform_info.c
@@ -72,6 +72,7 @@
MIC_INFO,
CUSTOM_MTMX_PARAMS,
CUSTOM_MTMX_PARAM_COEFFS,
+ EXTERNAL_DEVICE_SPECIFIC,
} section_t;
typedef void (* section_process_fn)(const XML_Char **attr);
@@ -95,6 +96,7 @@
static void process_mic_info(const XML_Char **attr);
static void process_custom_mtmx_params(const XML_Char **attr);
static void process_custom_mtmx_param_coeffs(const XML_Char **attr);
+static void process_external_dev(const XML_Char **attr);
static section_process_fn section_table[] = {
[ROOT] = process_root,
@@ -115,6 +117,7 @@
[MIC_INFO] = process_mic_info,
[CUSTOM_MTMX_PARAMS] = process_custom_mtmx_params,
[CUSTOM_MTMX_PARAM_COEFFS] = process_custom_mtmx_param_coeffs,
+ [EXTERNAL_DEVICE_SPECIFIC] = process_external_dev,
};
static section_t section;
@@ -460,6 +463,38 @@
return;
}
+static void process_external_dev(const XML_Char **attr)
+{
+ snd_device_t snd_device = SND_DEVICE_NONE;
+
+ if (strcmp(attr[0], "name") != 0) {
+ ALOGE("%s: 'name' not found", __func__);
+ goto done;
+ }
+
+ snd_device = platform_get_snd_device_index((char *)attr[1]);
+ if (snd_device < 0) {
+ ALOGE("%s: Device %s in %s not found, no ACDB ID set!",
+ __func__, (char *)attr[3], PLATFORM_INFO_XML_PATH);
+ goto done;
+ }
+
+ if (strcmp(attr[2], "usbid") != 0) {
+ ALOGE("%s: 'usbid' not found", __func__);
+ goto done;
+ }
+
+ if (strcmp(attr[4], "acdb_id") != 0) {
+ ALOGE("%s: 'acdb_id' not found", __func__);
+ goto done;
+ }
+
+ platform_add_external_specific_device(snd_device, (char *)attr[3], atoi((char *)attr[5]));
+
+done:
+ return;
+}
+
static void process_audio_effect(const XML_Char **attr, effect_type_t effect_type)
{
int index;
@@ -1204,6 +1239,11 @@
section = CUSTOM_MTMX_PARAM_COEFFS;
section_process_fn fn = section_table[section];
fn(attr);
+ } else if (strcmp(tag_name, "external_specific_dev") == 0) {
+ section = EXTERNAL_DEVICE_SPECIFIC;
+ } else if (strcmp(tag_name, "ext_device") == 0) {
+ section_process_fn fn = section_table[section];
+ fn(attr);
}
} else {
if(strcmp(tag_name, "config_params") == 0) {
@@ -1256,6 +1296,8 @@
section = ROOT;
} else if (strcmp(tag_name, "snd_devices") == 0) {
section = ROOT;
+ } else if (strcmp(tag_name, "external_specific_dev") == 0) {
+ section = ROOT;
} else if (strcmp(tag_name, "input_snd_device") == 0) {
section = SND_DEVICES;
} else if (strcmp(tag_name, "input_snd_device_mic_mapping") == 0) {