一、引入:
在Android中,应用进行音频回放或者录音时,最终在hal层需要选择用哪个输入/输出设备,而设备的加载,就跟audio_policy.conf息息相关,本博文分析的内容就是Android原生音频audio_policy.conf加载的过程(Android5.1)。
二、源码分析:
1.AudioPolicyService服务的启动:
与音频相关的服务AudioFlinger和AudioPolicyService都是在mediaserver这个进程中:
...
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
ALOGI("ServiceManager: %p", sm.get());
AudioFlinger::instantiate();
MediaPlayerService::instantiate();
CameraService::instantiate();
AudioPolicyService::instantiate();
SoundTriggerHwService::instantiate();
...
看一下AudioPolicyService::instantiate():
template<typename SERVICE>
class BinderService
{
public:
static status_t publish(bool allowIsolated = false) {
sp<IServiceManager> sm(defaultServiceManager());
return sm->addService(
String16(SERVICE::getServiceName()),
new SERVICE(), allowIsolated);
}
static void publishAndJoinThreadPool(bool allowIsolated = false) {
publish(allowIsolated);
joinThreadPool();
}
static void instantiate() { publish(); }
static status_t shutdown() { return NO_ERROR; }
private:
static void joinThreadPool() {
sp<ProcessState> ps(ProcessState::self());
ps->startThreadPool();
ps->giveThreadPoolName();
IPCThreadState::self()->joinThreadPool();
}
};
这是一个模板类,实际上调用的是publish()这个函数,看一下此函数的实现,向SM注册此服务,然后实例化AudioPolicyService,因为addService的第二个参数是强指针传参,所以紧接着会去调用onFirstRef()函数:
AudioPolicyService::AudioPolicyService()
: BnAudioPolicyService(), mpAudioPolicyDev(NULL), mpAudioPolicy(NULL),
mAudioPolicyManager(NULL), mAudioPolicyClient(NULL), mPhoneState(AUDIO_MODE_INVALID)
{
}
AudioPolicyService的构造其实什么事都没有干,但是要注意初始化参数列表中的这几个成员变量,但onFirstRef有干具体的事;
void AudioPolicyService::onFirstRef()
{
...
/* 1.实例化AudioPolicyClient */
mAudioPolicyClient = new AudioPolicyClient(this);
/* 2.实例化AudioPolicyManager */
mAudioPolicyManager = createAudioPolicyManager(mAudioPolicyClient);
...
}
因为AudioPolicyService是基于binder机制的C/S架构,所以,服务端建立起来之之后,自然不可缺少client端,AudioPolicyClient构造函数在AudioPolicyService.h中,记录了当前的服务AudioPolicyService,可以看到,client端获取audiopolicyservice的服务并不在构造函数中,而是另有他处:
AudioPolicyClient(AudioPolicyService *service) : mAudioPolicyService(service) {}
extern "C" AudioPolicyInterface* createAudioPolicyManager(
AudioPolicyClientInterface *clientInterface)
{
return new AudioPolicyManager(clientInterface);
}
总结来说,onFirstRef干的事是实例化了一个AudioPolicyClient对象,记录了服务的提供者AudioPolicyService,接着继续构造了AudioPolicyManager;
2.加载audio_policy.conf:
配置文件的加载就是在AudioPolicyManager的构造函数完成的,博文分析的conf文件在文章最后:
if (loadAudioPolicyConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE) != NO_ERROR) {
if (loadAudioPolicyConfig(AUDIO_POLICY_CONFIG_FILE) != NO_ERROR) {
ALOGE("could not load audio policy configuration file, setting defaults");
defaultAudioPolicyConfig();
}
}
如果代码中的两个路径都没有找到conf文件的话,就会直接生成一个,系统中的audio_policy.conf被读取之后,以profile的形式保存,后续打开/关闭设备的时候,就通过调用profile获取所有的配置参数;
重点分析一下loadAudioPolicyConfig函数:
status_t AudioPolicyManager::loadAudioPolicyConfig(const char *path)
{
cnode *root;
char *data;
/* 1.加载conf文件 */
data = (char *)load_file(path, NULL);
if (data == NULL) {
return -ENODEV;
}
/* 2.实例化一个数据储存链表 */
root = config_node("", "");
/* 3.读取conf,生成数据节点 */
config_load(root, data);
/* 4.加载模块 */
loadHwModules(root);
// legacy audio_policy.conf files have one global_configuration section
/* 5.加载全局配置 */
loadGlobalConfig(root, getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY));
/* 6.释放相关资源 */
config_free(root);
free(root);
free(data);
ALOGI("loadAudioPolicyConfig() loaded %s\n", path);
return NO_ERROR;
}
前面两步就是去读取文件中的内容,同时生成一个管理数据的链表,准备去生成profile,第三步就是去解析数据,解析方式有点复杂,没有详细看,大概的原理,就是以“{}”包围的部分识别为一组有效数据,然后储存起来,第四步就是重点了,根据关键字去生成profile:
void AudioPolicyManager::loadHwModules(cnode *root)
{
/* 识别audio_hw_modules关键字的数据块 */
cnode *node = config_find(root, AUDIO_HW_MODULE_TAG);
if (node == NULL) {
return;
}
node = node->first_child;
while (node) {
ALOGE("loadHwModules() loading module %s", node->name);
/* 加载模块 */
loadHwModule(node);
node = node->next;
}
}
首先是从profile中读取audio_hw_modules后面的数据块,注意这个module,后续代码中,加载动态库就是根据这个module名来的,从profile中可以看出来,一共有4个模块,分别是primary、a2dp、usb和r_submix,以primary为例,看下loadHwModule:
void AudioPolicyManager::loadHwModule(cnode *root)
{
status_t status = NAME_NOT_FOUND;
cnode *node;
sp<HwModule> module = new HwModule(root->name);
...
node = config_find(root, OUTPUTS_TAG);
if (node != NULL) {
node = node->first_child;
while (node) {
ALOGE("loadHwModule() loading output %s", node->name);
status_t tmpStatus = module->loadOutput(node);
if (status == NAME_NOT_FOUND || status == NO_ERROR) {
status = tmpStatus;
}
node = node->next;
}
}
...
}
primary下属的关键字数据块有两个,分别是outputs和inputs,找到outputs数据块之后,调用loadOutput去生成profile,outputs下面一共有4个profile,分别是primary、hw_av_sync、hw_compress和hw_av_sync_compress:
status_t AudioPolicyManager::HwModule::loadOutput(cnode *root)
{
cnode *node = root->first_child;
sp<IOProfile> profile = new IOProfile(String8(root->name), AUDIO_PORT_ROLE_SOURCE, this);
while (node) {
if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
profile->loadSamplingRates((char *)node->value);
} else if (strcmp(node->name, FORMATS_TAG) == 0) {
profile->loadFormats((char *)node->value);
} else if (strcmp(node->name, CHANNELS_TAG) == 0) {
profile->loadOutChannels((char *)node->value);
} else if (strcmp(node->name, DEVICES_TAG) == 0) {
profile->mSupportedDevices.loadDevicesFromName((char *)node->value,
mDeclaredDevices);
} else if (strcmp(node->name, FLAGS_TAG) == 0) {
profile->mFlags = parseOutputFlagNames((char *)node->value);
} else if (strcmp(node->name, GAINS_TAG) == 0) {
profile->loadGains(node);
}
node = node->next;
}
ALOGW_IF(profile->mSupportedDevices.isEmpty(),
"loadOutput() invalid supported devices");
ALOGW_IF(profile->mChannelMasks.size() == 0,
"loadOutput() invalid supported channel masks");
ALOGW_IF(profile->mSamplingRates.size() == 0,
"loadOutput() invalid supported sampling rates");
ALOGW_IF(profile->mFormats.size() == 0,
"loadOutput() invalid supported formats");
if (!profile->mSupportedDevices.isEmpty() &&
(profile->mChannelMasks.size() != 0) &&
(profile->mSamplingRates.size() != 0) &&
(profile->mFormats.size() != 0)) {
ALOGE("loadOutput() adding output Supported Devices %04x, mFlags %04x",
profile->mSupportedDevices.types(), profile->mFlags);
mOutputProfiles.add(profile);
return NO_ERROR;
} else {
return BAD_VALUE;
}
}
这里就根据具体的配置去生成profile,然后添加到mOutputProfiles中就行了;
3.根据module去加载动态库:
回到AudioPolicyManager的构造函数,在loadAudioPolicyConfig成功之后,接下来要做的事就是去加载各个module对应的动态库,这是通过loadHwModule@AudioPolicyManager来完成的:
mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->mName);
mpClientInterface前面已经分析过,指向的是类对象AudioPolicyClientInterface,注意成员函数的实现是在AudioPolicyClientImpl.cpp中,找到loadHwModule:
audio_module_handle_t AudioPolicyService::AudioPolicyClient::loadHwModule(const char *name)
{
/* 1.获取audio_flinger服务 */
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
if (af == 0) {
ALOGW("%s: could not get AudioFlinger", __func__);
return 0;
}
/* 2.通过audioflinger去加载动态库 */
return af->loadHwModule(name);
}
进入audioflinger,会继续调用loadHwModule_l:
audio_module_handle_t AudioFlinger::loadHwModule_l(const char *name)
{
...
/* 动态库的加载 */
int rc = load_audio_interface(name, &dev);
if (rc) {
ALOGI("loadHwModule() error %d loading module %s ", rc, name);
return 0;
}
...
}
继续往下跟踪:
static int load_audio_interface(const char *if_name, audio_hw_device_t **dev)
{
const hw_module_t *mod;
int rc;
/* 根据传入的module名生成动态库 */
rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod);
ALOGE_IF(rc, "%s couldn't load audio hw module %s.%s (%s)", __func__,
AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc));
if (rc) {
goto out;
}
rc = audio_hw_device_open(mod, dev);
ALOGE_IF(rc, "%s couldn't open audio hw device in %s.%s (%s)", __func__,
AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc));
if (rc) {
goto out;
}
if ((*dev)->common.version < AUDIO_DEVICE_API_VERSION_MIN) {
ALOGE("%s wrong audio hw device version %04x", __func__, (*dev)->common.version);
rc = BAD_VALUE;
goto out;
}
return 0;
out:
*dev = NULL;
return rc;
}
重点分析hw_get_module_by_class,传入的名字是“audio” + module,然后根据property_get的结果去拼接最终的库名:
int hw_get_module_by_class(const char *class_id, const char *inst,
const struct hw_module_t **module)
{
...
/* 传入的名字name经过拼接,为“audio.primary” */
...
/* 1.查看属性“ro.hardware.audio.primary”结果 */
snprintf(prop_name, sizeof(prop_name), "ro.hardware.%s", name);
if (property_get(prop_name, prop, NULL) > 0) {
if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
goto found;
}
}
/* 2.查看VARIANT_KEYS是否有对应属性 */
for (i=0 ; i<HAL_VARIANT_KEYS_COUNT; i++) {
if (property_get(variant_keys[i], prop, NULL) == 0) {
continue;
}
if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
goto found;
}
}
/* 3.如果都没有,就为default */
if (hw_module_exists(path, sizeof(path), name, "default") == 0) {
goto found;
}
}
在我的调试的镜像中,第二条ro.hardware属性值为bigfish,所以加载的库为“audio.primary.bigfish.so”,可以看到,库的加载是有优先级的,如果module名相同,而后缀不同的话,那么就会根据优先级进行加载,比如:“audio.primary.bigfish.so”和“audio.primary.default.so”同时存在,加载的就会是前者;
4.去hal层打开输入/输出流:
回到AudioPolicyManager的构造函数,既然已经加载了动态库,接下来就是尝试通过audioflinger去底层打开输入输出流,这里以输出为例:
status_t status = mpClientInterface->openOutput(outProfile->mModule->mHandle,
&output,
&config,
&outputDesc->mDevice,
String8(""),
&outputDesc->mLatency,
outputDesc->mFlags);
mpClientInterface前面已经分析过,指向的是类对象AudioPolicyClientInterface,注意成员函数的实现是在AudioPolicyClientImpl.cpp中,找到openOutput:
status_t AudioPolicyService::AudioPolicyClient::openOutput(audio_module_handle_t module,
audio_io_handle_t *output,
audio_config_t *config,
audio_devices_t *devices,
const String8& address,
uint32_t *latencyMs,
audio_output_flags_t flags)
{
/* 1.获取audio_flinger服务 */
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
if (af == 0) {
ALOGW("%s: could not get AudioFlinger", __func__);
return PERMISSION_DENIED;
}
/* 2.通过audioflinger去打开输出设备 */
return af->openOutput(module, output, config, devices, address, latencyMs, flags);
}
这里就可以看到,audiopolicy最终还是通过audioflinger去打开输出设备;
openOutput会继续调用openOutput_l:
sp<AudioFlinger::PlaybackThread> AudioFlinger::openOutput_l(audio_module_handle_t module,
audio_io_handle_t *output,
audio_config_t *config,
audio_devices_t devices,
const String8& address,
audio_output_flags_t flags)
{
/* 1.找到合适的device */
AudioHwDevice *outHwDev = findSuitableHwDev_l(module, devices);
if (outHwDev == NULL) {
return 0;
}
/* 2.去hal层打开设备 */
status_t status = hwDevHal->open_output_stream(hwDevHal,
*output,
devices,
flags,
config,
&outStream,
address.string());
/* 3.实例化输出流并创建一个thread */
mPlaybackThreads.add(*output, thread);
return thread;
...
}
看一下findSuitableHwDev_l:
AudioFlinger::AudioHwDevice* AudioFlinger::findSuitableHwDev_l(
audio_module_handle_t module,
audio_devices_t devices)
{
// if module is 0, the request comes from an old policy manager and we should load
// well known modules
if (module == 0) {
ALOGW("findSuitableHwDev_l() loading well know audio hw modules");
for (size_t i = 0; i < ARRAY_SIZE(audio_interfaces); i++) {
loadHwModule_l(audio_interfaces[i]);
}
// then try to find a module supporting the requested device.
for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
AudioHwDevice *audioHwDevice = mAudioHwDevs.valueAt(i);
audio_hw_device_t *dev = audioHwDevice->hwDevice();
if ((dev->get_supported_devices != NULL) &&
(dev->get_supported_devices(dev) & devices) == devices)
return audioHwDevice;
}
} else {
// check a match for the requested module handle
AudioHwDevice *audioHwDevice = mAudioHwDevs.valueFor(module);
if (audioHwDevice != NULL) {
return audioHwDevice;
}
}
return NULL;
}
mediaserver启动场景,只会走到else里面去,直接通过module即可找到AudioHwDevice;
三、audio_policy.conf源码:
#
# Audio policy configuration for generic device builds (goldfish audio HAL - emulator)
#
# Global configuration section: lists input and output devices always present on the device
# as well as the output device selected by default.
# Devices are designated by a string that corresponds to the enum in audio.h
global_configuration {
attached_output_devices AUDIO_DEVICE_OUT_SPEAKER
default_output_device AUDIO_DEVICE_OUT_SPEAKER
attached_input_devices AUDIO_DEVICE_IN_BUILTIN_MIC
}
# audio hardware module section: contains descriptors for all audio hw modules present on the
# device. Each hw module node is named after the corresponding hw module library base name.
# For instance, "primary" corresponds to audio.primary..so.
# The "primary" module is mandatory and must include at least one output with
# AUDIO_OUTPUT_FLAG_PRIMARY flag.
# Each module descriptor contains one or more output profile descriptors and zero or more
# input profile descriptors. Each profile lists all the parameters supported by a given output
# or input stream category.
# The "channel_masks", "formats", "devices" and "flags" are specified using strings corresponding
# to enums in audio.h and audio_policy.h. They are concatenated by use of "|" without space or "\n".
#device sr changed from 44100 to 48000 to adapt chip
audio_hw_modules {
primary {
outputs {
primary {
sampling_rates 48000
channel_masks AUDIO_CHANNEL_OUT_STEREO
formats AUDIO_FORMAT_PCM_16_BIT
devices AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_HDMI
flags AUDIO_OUTPUT_FLAG_PRIMARY
}
hw_av_sync {
sampling_rates 8000|11025|16000|22050|24000|32000|44100|48000
channel_masks AUDIO_CHANNEL_OUT_MONO|AUDIO_CHANNEL_OUT_STEREO
formats AUDIO_FORMAT_PCM_16_BIT
devices AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_HDMI
flags AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_HW_AV_SYNC
}
hw_compress {
sampling_rates 8000|11025|16000|22050|24000|32000|44100|48000
channel_masks AUDIO_CHANNEL_OUT_STEREO|AUDIO_CHANNEL_OUT_MONO|AUDIO_CHANNEL_OUT_5POINT1|AUDIO_CHANNEL_OUT_7POINT1
formats AUDIO_FORMAT_AC3|AUDIO_FORMAT_E_AC3
devices AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_HDMI
flags AUDIO_OUTPUT_FLAG_DIRECT
}
hw_av_sync_compress {
sampling_rates 8000|11025|16000|22050|24000|32000|44100|48000
channel_masks AUDIO_CHANNEL_OUT_STEREO|AUDIO_CHANNEL_OUT_MONO|AUDIO_CHANNEL_OUT_5POINT1|AUDIO_CHANNEL_OUT_7POINT1
formats AUDIO_FORMAT_AC3|AUDIO_FORMAT_E_AC3
devices AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_HDMI
flags AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_HW_AV_SYNC
}
}
inputs {
primary {
sampling_rates 8000|11025|16000|22050|24000|32000|44100|48000
channel_masks AUDIO_CHANNEL_IN_MONO
formats AUDIO_FORMAT_PCM_16_BIT
devices AUDIO_DEVICE_IN_BUILTIN_MIC
}
}
}
a2dp {
outputs {
a2dp {
sampling_rates 44100|48000
channel_masks AUDIO_CHANNEL_OUT_STEREO
formats AUDIO_FORMAT_PCM_16_BIT
devices AUDIO_DEVICE_OUT_ALL_A2DP
}
}
}
usb {
outputs {
usb_device {
sampling_rates dynamic
channel_masks dynamic
formats dynamic
devices AUDIO_DEVICE_OUT_USB_DEVICE
}
}
inputs {
usb_device {
sampling_rates dynamic
channel_masks dynamic
formats dynamic
devices AUDIO_DEVICE_IN_USB_DEVICE
}
}
}
r_submix {
outputs {
submix {
sampling_rates 48000
channel_masks AUDIO_CHANNEL_OUT_STEREO
formats AUDIO_FORMAT_PCM_16_BIT
devices AUDIO_DEVICE_OUT_REMOTE_SUBMIX
}
}
inputs {
submix {
sampling_rates 48000
channel_masks AUDIO_CHANNEL_IN_STEREO
formats AUDIO_FORMAT_PCM_16_BIT
devices AUDIO_DEVICE_IN_REMOTE_SUBMIX
}
}
}
}
四、启动总结:
Mediaserver进程会去创建audiopolicyservice的服务,然后在服务中会去实例化audiopolicymanager,实际上,audiopolicymanager拥有audiopolicyservice的代理权,当涉及具体动作的时候,调用audioflinger去完成。