赞
踩
一、引入:
在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文件在文章最后:
/* 设定默认设备的devicetype为AUDIO_DEVICE_OUT_SPEAKER,后续代码去hal层打开设备的时候回根据此默认设备类型进行过滤 */
mDefaultOutputDevice = new DeviceDescriptor(String8(""), AUDIO_DEVICE_OUT_SPEAKER);
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去底层打开输入输出流,这里会设置一些过滤状态,我们从前面加载profile可以看到,devicetype或者flag等描述后面会支持多属性,所以在打开之前会进行过滤,flag为不支持混音的,devicetype优先选择前面定义的AUDIO_DEVICE_OUT_SPEAKER,如果不支持该类型,再根据profile来,这里以输出为例:
... /* flag过滤,仅打开不支持混音的profile */ if ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) { continue; } ... /* devicetype优先打开AUDIO_DEVICE_OUT_SPEAKER */ if ((profileType & mDefaultOutputDevice->mDeviceType) != AUDIO_DEVICE_NONE) { profileType = mDefaultOutputDevice->mDeviceType; } else { /* 不支持AUDIO_DEVICE_OUT_SPEAKER ,则根据profile来 */ for (size_t k = 0; k < outProfile->mSupportedDevices.size(); k++) { profileType = outProfile->mSupportedDevices[k]->mDeviceType; if ((profileType & outputDeviceTypes) != 0) { break; } } } if ((profileType & outputDeviceTypes) == 0) { continue; } ... /* client端去调用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.<device>.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去完成。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。