1.1.1 音频设备的管理
虽然AudioFlinger实体已经成功创建并初始化,但到目前为止它还是一块静态的内存空间,没有涉及到具体的工作。
从职能分布上来讲,AudioPolicyService是策略的制定者,比如什么时候打开音频接口设备、某种Stream类型的音频对应什么设备等等。而AudioFlinger则是策略的执行者,例如具体如何与音频设备通信,如何维护现有系统中的音频设备,以及多个音频流的混音如何处理等等都得由它来完成。
目前Audio系统中支持的音频设备接口(Audio Interface)分为三大类,即:
/*frameworks/av/services/audioflinger/AudioFlinger.cpp*/
static const char * const audio_interfaces[] = {
AUDIO_HARDWARE_MODULE_ID_PRIMARY, //主音频设备,必须存在
AUDIO_HARDWARE_MODULE_ID_A2DP, //蓝牙A2DP音频
AUDIO_HARDWARE_MODULE_ID_USB, //USB音频,早期的版本不支持
};
每种音频设备接口由一个对应的so库提供支持。那么AudioFlinger怎么会知道当前设备中支持上述的哪些接口,每种接口又支持哪些具体的音频设备呢?这是AudioPolicyService的责任之一,即根据用户配置来指导AudioFlinger加载设备接口。
当AudioPolicyManagerBase(AudioPolicyService中持有的Policy管理者,后面小节有详细介绍)构造时,它会读取厂商关于音频设备的描述文件(audio_policy.conf),然后据此来打开以上三类音频接口(如果存在的话)。这一过程最终会调用loadHwModule@AudioFlinger,如下所示:
/*frameworks/av/services/audioflinger*/
audio_module_handle_t AudioFlinger::loadHwModule(const char *name)/*name就是前面audio_interfaces 数组
成员中的字符串*/
{
if (!settingsAllowed()) {
return 0;
}
Mutex::Autolock _l(mLock);
returnloadHwModule_l(name);
}
这个函数没有做实质性的工作,只是执行了加锁动作,然后接着调用下面的函数:
audio_module_handle_t AudioFlinger::loadHwModule_l(const char *name)
{
/*Step 1. 是否已经添加了这个interface?*/
for (size_t i = 0; i <mAudioHwDevs.size(); i++) {
if(strncmp(mAudioHwDevs.valueAt(i)->moduleName(), name, strlen(name)) == 0) {
ALOGW("loadHwModule() module %s already loaded", name);
returnmAudioHwDevs.keyAt(i);
}
}
/*Step 2. 加载audio interface*/
audio_hw_device_t *dev;
int rc =load_audio_interface(name, &dev);
…
/*Step 3. 初始化*/
mHardwareStatus = AUDIO_HW_INIT;
rc = dev->init_check(dev);
mHardwareStatus = AUDIO_HW_IDLE;
…
if ((mMasterVolumeSupportLvl !=MVS_NONE) && (NULL != dev->set_master_volume)) {
AutoMutex lock(mHardwareLock);
mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
dev->set_master_volume(dev, mMasterVolume);
mHardwareStatus = AUDIO_HW_IDLE;
}
/*Step 4. 添加到全局变量中*/
audio_module_handle_t handle = nextUniqueId();
mAudioHwDevs.add(handle,new AudioHwDevice(name, dev));
return handle;
}
Step1@ loadHwModule_l. 首先查找mAudioHwDevs是否已经添加了变量name所指示的audio interface,如果是的话直接返回。第一次进入时mAudioHwDevs的size为0,所以还会继续往下执行。
Step2@ loadHwModule_l. 加载指定的audiointerface,比如“primary”、“a2dp”或者“usb”。函数load_audio_interface用来加载设备所需的库文件,然后打开设备并创建一个audio_hw_device_t实例。音频接口设备所对应的库文件名称是有一定格式的,比如a2dp的模块名可能是audio.a2dp.so或者audio.a2dp.default.so等等。查找路径主要有两个,即:
/** Base path of the hal modules */
#define HAL_LIBRARY_PATH1 "/system/lib/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib/hw"
当然,因为Android是完全开源的,各开发商可以根据自己的需要来进行相应的修改,比如下面是某手机设备的音频库截图: