1.概述
上篇文章,我们通过分析snd_card_name = mixer_get_name(adev->mixer);这句代码,我们拿到了声卡名字,详情见以下超链接:
ACDB文件加载流程(一)
然后今天接着分析void *platform_init(struct audio_device *adev)函数,分析我们拿到声卡名之后的一波骚操作;
其代码路径是:
hardware\qcom\audio\hal\msm8916\platform.c
2.代码调用流程
下面的信息量可能比较大,你们用SI追下代码,以下是代码注解;
//把声卡名包含的平台信息提取,存储到hardware_info结构里面,最终存到platform_data 结构里面
static void update_hardware_info_8x16(struct hardware_info *hw_info,
const char *snd_card_name)
--> my_data->hw_info = hw_info_init(snd_card_name);
-> update_hardware_info_8x16(hw_info, snd_card_name);
//根据声卡名字,绑定对应的codec以及mixer_path XML文件
--> query_platform(snd_card_name, mixer_xml_path);
-> audio_extn_read_xml(adev, snd_card_num, mixer_xml_path,
MIXER_XML_PATH_AUXPCM) == -ENOSYS)
//如果找到这个蓝牙驱动ath3k if (!strncmp(bt_soc, "ath3k", sizeof("ath3k")))
->adev->audio_route = audio_route_init(mixer_card,
mixer_xml_path_auxpcm);存到audio_device
//否则走下面
-> adev->audio_route = audio_route_init(mixer_card, mixer_xml_path);
//这个根据声卡名把外部coedec的标志位置1:is_external_codec = true;
-->update_codec_type(snd_card_name);
//这是是配置立体声的,对应高通acdb里面的stereo音效
-->check_and_get_wsa_info((char *)snd_card_name, &wsaCount, &is_wsa_combo_supported)
//高通hifi音效需要收费,这个没接触过
-->ret = audio_extn_is_hifi_audio_supported();
-->my_data->acdb_init = (acdb_init_t)dlsym(my_data->acdb_handle,
"acdb_loader_init_v2");
代码走到这一步就特么找到重点了,HAL的platform.c会 通过dlsym加载私有代码库的acdb_loader_init_v2函数,
acdb_loader_init_v2函数原型在下面,路径如下:
vendor\qcom\proprietary\mm-audio\audio-acdb-util\acdb-loader\src\family-b\acdb-loader.c
audio_route_init函数在system\media\audio_route\audio_route.c它会被封装成libaudioroute.so库,
该文件用于解析用户空间的音频通道配置文件(mixer_xml_path对应的XML由声卡名字绑定),
然后由ALSA来配置音频通道。
3. 重点函数原型
static void update_hardware_info_8x16(struct hardware_info *hw_info,
const char *snd_card_name)
{
if (!strcmp(snd_card_name, "msm8x16-snd-card")) {
strlcpy(hw_info->type, "", sizeof(hw_info->type));
strlcpy(hw_info->name, "msm8x16", sizeof(hw_info->name));
hw_info->snd_devices = NULL;
hw_info->num_snd_devices = 0;
strlcpy(hw_info->dev_extn, "", sizeof(hw_info->dev_extn));
....
}
void *hw_info_init(const char *snd_card_name)
{
struct hardware_info *hw_info;
hw_info = malloc(sizeof(struct hardware_info));
if (!hw_info) {
ALOGE("failed to allocate mem for hardware info");
return NULL;
}
if (strstr(snd_card_name, "msm8x16") || strstr(snd_card_name, "msm8939") ||
strstr(snd_card_name, "msm8909") || strstr(snd_card_name, "msm8952") ||
strstr(snd_card_name, "msm8976") || strstr(snd_card_name, "msm8953") ||
strstr(snd_card_name, "msm8937") || strstr(snd_card_name, "msm8917") ||
strstr(snd_card_name, "msm8940") || strstr(snd_card_name, "msm8920") ||
strstr(snd_card_name, "msmfalcon")) {
ALOGV("8x16 - variant soundcard");
update_hardware_info_8x16(hw_info, snd_card_name);
} else {
ALOGE("%s: Unsupported target %s:",__func__, snd_card_name);
free(hw_info);
hw_info = NULL;
}
return hw_info;
}
static void query_platform(const char *snd_card_name,
char *mixer_xml_path)
{
if (!strncmp(snd_card_name, "msm8x16-snd-card-mtp",
sizeof("msm8x16-snd-card-mtp"))) {
strlcpy(mixer_xml_path, MIXER_XML_PATH_MTP,
sizeof(MIXER_XML_PATH_MTP));
msm_device_to_be_id = msm_device_to_be_id_internal_codec;
msm_be_id_array_len =
sizeof(msm_device_to_be_id_internal_codec) /
sizeof(msm_device_to_be_id_internal_codec[0]);
....
}
int32_t audio_extn_read_xml(struct audio_device *adev, uint32_t mixer_card,
const char* mixer_xml_path,
const char* mixer_xml_path_auxpcm)
{
char bt_soc[128];
bool wifi_init_complete = false;
int sleep_retry = 0;
while (!wifi_init_complete && sleep_retry < MAX_SLEEP_RETRY) {
property_get("qcom.bluetooth.soc", bt_soc, NULL);
if (strncmp(bt_soc, "unknown", sizeof("unknown"))) {
wifi_init_complete = true;
} else {
usleep(WIFI_INIT_WAIT_SLEEP*1000);
sleep_retry++;
}
}
if (!strncmp(bt_soc, "ath3k", sizeof("ath3k")))
adev->audio_route = audio_route_init(mixer_card, mixer_xml_path_auxpcm);
else
adev->audio_route = audio_route_init(mixer_card, mixer_xml_path);
return 0;
}
4. 补充说明
#ifndef AUXPCM_BT_ENABLED
#define audio_extn_read_xml(adev, mixer_card, MIXER_XML_PATH, \
MIXER_XML_PATH_AUXPCM) (-ENOSYS)
#else
int32_t audio_extn_read_xml(struct audio_device *adev, uint32_t mixer_card,
const char* mixer_xml_path,
const char* mixer_xml_path_auxpcm);
#endif /* AUXPCM_BT_ENABLED */
这里补充说明:ath3k is the Linux Bluetooth driver for Atheros AR3011/AR3012 Bluetooth chipsets.
我觉得这个ath3k是一个AUX接口相关的蓝牙驱动,这个一般是用在汽车上的,目前我没有接触到,而且解析对应的这个XML文件mixer_paths_auxpcm.xml文件没有从高通的源代码中找到,但是驱动是存在的,代码位置是:
LA.UM.5.6\kernel\msm-3.18\drivers\bluetooth\ath3k.c
MODULE_AUTHOR("Atheros Communications");
MODULE_DESCRIPTION("Atheros AR30xx firmware driver");
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
MODULE_FIRMWARE(ATH3K_FIRMWARE);
本文到此结束,下一篇重点分析acdb_loader_init_v2函数以及把acdb的调用做个总结.
5. 作者注
/******
@article{Linux Audio Driver,
Author = { 1byte ≠ 8bit},
Year = { 2020},
}
******/