首先代码还是android7,之前两篇文章提到,拿到声卡名字以及在platform.c里面通过dlsym的方式,加载acdb_loader_init_v2函数, 今天继续分析;
代码路径:
vendor\qcom\proprietary\mm-audio\audio-acdb-util\acdb-loader\src\family-b\acdb-loader.c
int acdb_loader_init_v2(char *snd_card_name, char *cvd_version, int metaInfoKey){
…
{
int acdb_loader_init_v2(char *snd_card_name, char *cvd_version, int metaInfoKey)
{
int ret = 0;
int i;
int result = 0;
AcdbVocProcGainDepVolTblSizeV2CmdType vocvoltablesize;
AcdbSizeResponseType response;
AcdbInitCmdType acdb_init_cmd; //重点结构,后面分析
AcdbGetMetaInfoSizeCmdType metaInfoSizeCmd;
AcdbSizeResponseType metaInfoSize;
pthread_mutex_lock(&loader_mutex); //上锁
if (acdb_init_ref_cnt != 0) {
acdb_init_ref_cnt++;
ALOGD("ACDB -> already initialized, exit");
goto done;
}
list_init(&aud_vol_idx_list.list); // 链表初始化,acdb id,app id相关,
if (acdb_load_files(&acdb_init_cmd, snd_card_name) <= 0) { //acdb_load_files是加载
//acdb文件的重点
LOGE("ACDB -> Could not load .acdb files!\n");
ret = -ENODEV;
goto done;
}
LOGD("ACDB -> ACDB_CMD_INITIALIZE_V2\n");
ret = acdb_ioctl(ACDB_CMD_INITIALIZE_V2, //初始化acdb文件
(const uint8_t *)&acdb_init_cmd, sizeof(acdb_init_cmd), NULL, 0);
......
acdb_rtac_init(); //接收/发送来自QACT的数据,并将其发送/接收到RTAC驱动程序
//(用于设备和QACT通信)
......
acdb_loader_send_common_custom_topology(); //加载音频校准的API的数据并推送到DSP
if (send_meta_info(metaInfoKey) < 0)
LOGD("ACDB -> send_meta_info failed");
current_feature_set = ACDB_VOCVOL_FID_DEFAULT;
is_initialized = true; //bool变量,acdb加载一波之后置true
parse_codec_type(snd_card_name); //声卡类型解析
LOGD("ACDB -> init done!\n");
acdb_init_ref_cnt++;
done:
pthread_mutex_unlock(&loader_mutex); //释放锁
return ret;
}
if (acdb_load_files(&acdb_init_cmd, snd_card_name) <= 0)
这句代码是加载acdb 的核心,我们先看一下这个变量acdb_init_cmd;
AcdbInitCmdType acdb_init_cmd;
//Structure to hold an individual ACDB file name and path.
LA.UM.5.6\vendor\qcom\proprietary\mm-audio\audcal\family-b\acdb\inc\acdb.h
struct _AcdbFileName{
uint32_t fileNameLen;
//< Full file path name length.
char fileName[ACDB_FILENAME_MAX_CHARS];
//< Array that holds the ACDB file path and name. The file size cannot
// exceed 256 characters, including the NULL-termiated character.
//@newpagetable
}
typedef struct _AcdbInitCmdType AcdbInitCmdType;
#include "acdb_begin_pack.h"
// Query command structure for the command ACDB_CMD_INITIALIZE_V2.
struct _AcdbInitCmdType {
uint32_t nNoOfFiles;
//< Number of ACDB files to read from the acdbFiles array.
AcdbFileName acdbFiles[20];
//< Array of ACDB file names. A maximum of 20 ACDB files can be
// provided at one time to be initialized.
}
我们可以看到acdb_init_cmd是AcdbInitCmdType结构类型的,其存储了ACDB的文件名字以及
ACDB文件的位置;
接下来进去acdb_load_files函数,
vendor\qcom\proprietary\mm-audio\audio-acdb-util\acdb-loader\src\family-b\acdb-loader.c
static int acdb_load_files(AcdbInitCmdType *acdb_init_cmd, char * snd_card_name)
{
int result = 0;
result = get_files_from_properties(acdb_init_cmd);
if (result > 0)
goto done;
result = get_files_from_device_tree(acdb_init_cmd, snd_card_name);
done:
return result;
}
先分析get_files_from_properties函数,
vendor\qcom\proprietary\mm-audio\audio-acdb-util\acdb-loader\src\family-b\acdb-loader.c
static int get_files_from_properties(AcdbInitCmdType *acdb_init_cmd)
{
int i = 0;
int prop_len;
char prop_name[24];
for (i=0; i < MAX_ACDB_FILES; i++) {
if (snprintf(prop_name, sizeof(prop_name), "persist.audio.calfile%d", i) < 0)
goto done;
prop_len = property_get(prop_name, acdb_init_cmd->acdbFiles[i].fileName, NULL);
if (prop_len <= 0)
goto done;
acdb_init_cmd->acdbFiles[i].fileNameLen =
strlen(acdb_init_cmd->acdbFiles[i].fileName);
LOGD("ACDB -> Prop Load file: %s\n", acdb_init_cmd->acdbFiles[i].fileName);
}
done:
acdb_init_cmd->nNoOfFiles = i;
return i;
}
这段代码很奇怪,首先这个persist.audio.calfile默认代码就没有配置(当然可能是作为调试用代码),
从我的理解来看,他会通过snprintf把"persist.audio.calfile0"存到字符数组prop_name里面去,
#define MAX_ACDB_FILES 20
这个常量最大20,所以字符最多为"persist.audio.calfile20",最大占用23个char 型位置,字符串最后补个\0的话,刚刚数组长度为24,那么其输出必然不被截断,返回值固定为24;
之后代码又通过property_get的方式,把刚才存到prop_name的值存到acdb_init_cmd->acdbFiles[i].fileName里面,而我们从刚才的重点的那个结构AcdbInitCmdType,
struct _AcdbInitCmdType {
uint32_t nNoOfFiles;
//< Number of ACDB files to read from the acdbFiles array.
AcdbFileName acdbFiles[20];
//< Array of ACDB file names. A maximum of 20 ACDB files can be
// provided at one time to be initialized.
}
可以看出(从注释也行),其明明应该存储acdb 文件名字,所以这段代码很诡异,当时实际调试由于这个属性persist.audio.calfilem没有配置(从adb shell 进入设备,然后getprop persist.audio.calfilem没有返回值)可以看出,这段代码根本没有走到;
然后我们回到static int acdb_load_files(AcdbInitCmdType *acdb_init_cmd, char * snd_card_name)这个函数继续分析:
result = get_files_from_device_tree(acdb_init_cmd, snd_card_name);
先把这个 主要贴下来(只能删减写,不然这篇还写不完,发现CSDN有篇幅限制),如下:
static int get_files_from_device_tree(AcdbInitCmdType *acdb_init_cmd, char *snd_card_name)
{
int result = 0;
char dir_path[300];
char board_type[64] = DEFAULT_BOARD;
FILE *fp = NULL;
/* Get Board type */
fp = fopen("/sys/devices/soc0/hw_platform","r");
if (fp == NULL)
fp = fopen("/sys/devices/system/soc/soc0/hw_platform","r");
if (fp == NULL)
LOGE("ACDB -> Error: Couldn't open hw_platform\n");
else if (fgets(board_type, sizeof(board_type), fp) == NULL)
LOGE("ACDB -> Error: Couldn't get board type\n");
else if (board_type[(strlen(board_type) - 1)] == '\n')
board_type[(strlen(board_type) - 1)] = '\0';
if (fp != NULL)
fclose(fp);
/* get files from form factor & soundcard independant path */
result = get_acdb_files_in_directory(acdb_init_cmd, ACDB_BIN_PATH);
if (result >= 0)
LOGD("ACDB -> found %d form factor & soundcard independant files\n",
result);
if (result > MAX_INDEPENDANT_ACDB_FILES)
goto done;
/* Try board directory with soundcard name */
if (snd_card_name != NULL) {
result = snprintf(dir_path, sizeof(dir_path), "%s/%s/%s",
ACDB_BIN_PATH, board_type, snd_card_name);
if (result < 0) {
LOGE("ACDB -> Error: snprintf failed for snd card %s, error: %d\n",
snd_card_name, result);
result = -ENODEV;
goto done;
}
result = get_acdb_files_in_directory(acdb_init_cmd, dir_path);
if (result > 0)
goto done;
}
......
}
高通代码上来就给你个注释:
/* Get Board type */
fp = fopen("/sys/devices/soc0/hw_platform","r");
if (fp == NULL)
fp = fopen("/sys/devices/system/soc/soc0/hw_platform","r");
if (fp == NULL)
LOGE("ACDB -> Error: Couldn't open hw_platform\n");
else if (fgets(board_type, sizeof(board_type), fp) == NULL)
LOGE("ACDB -> Error: Couldn't get board type\n");
else if (board_type[(strlen(board_type) - 1)] == '\n')
board_type[(strlen(board_type) - 1)] = '\0';
if (fp != NULL)
fclose(fp);
board_type,这个代码里面默认配置的是MTP:
~/LA.UM.5.6$ grep -nr "DEFAULT_BOARD" ./vendor/ ./hardware/
./vendor/qcom/proprietary/mm-audio/audio-acdb-util/acdb-loader/Android.mk:17:
libacdbloader-def += -D DEFAULT_BOARD=\"MTP\"
./vendor/qcom/proprietary/mm-audio/audio-acdb-util/acdb-loader/src/family-b/acdb-loader.c
:616: char board_type[64] = DEFAULT_BOARD;
然后经过fopen的读取之后,我们能够获取到他的值是QRD,这玩意是高通CPU的平台信息,芯片内部
有一段空间是存储这个平台信息的,抽空俺也可以分析一波(之前有了解,但是忘了,信息好像是从
modem那边传过来的);随便找台设备,cat 一下这个节点值,我们就知道是QRD了。
/* get files from form factor & soundcard independant path */
result = get_acdb_files_in_directory(acdb_init_cmd, ACDB_BIN_PATH);
if (result >= 0)
LOGD("ACDB -> found %d form factor & soundcard independant files\n",
result);
if (result > MAX_INDEPENDANT_ACDB_FILES)
goto done;
后面的代码几乎都是get_acdb_files_in_directory函数在跑了,
ACDB_BIN_PATH在android 7是 设备里面的/etc/acdbdata/
result = get_acdb_files_in_directory(acdb_init_cmd, ACDB_BIN_PATH);
这个代码的意思就是,先在设备里面的etc/acdbdata/目录下面找,能不能找到那八个文件?(一般是8个),找到了goto done;函数跑完,找不到,走下一个判断;
result = snprintf(dir_path, sizeof(dir_path), "%s/%s/%s",
ACDB_BIN_PATH, board_type, snd_card_name);
接下来看你能否在/etc/acdbdata/QRD/msm8953-sku3-snd-card下面找到这个acdb文件;之后就是依次查找: /etc/acdbdata/QRD/ -> /etc/acdbdata/MTP/msm8953-sku3-snd-card ->
/etc/acdbdata/MTP -> /etc
总之,按照这个流程在设备里面找这个参数,按代码顺序,谁先找到就加载那个位置的acdb文件。
补充: 这个acdb的文件由系统编到设备目录下;
其实整个acdb 文件的加载流程如下图所示:
那么我们知道这个有啥用呢,其实在实际研发过程中,会遇到不得不使用同一套软件而兼容不同硬件状态的情况,具体可参考下面这位博主的博客,我就不多聊了。
https://blog.csdn.net/crow_ch/article/details/103886156
感谢您的阅读,本文OVER!