摘要:
Android音频策略中的音量控制方面主分为以下几点:
1.软件音量曲线和硬件音量曲线的加载过程及修改方法
2.音量调节过程的实现
3.音频流类型与其别名的对照关系
一、软音量曲线的加载及修改
概述:
在运行AudioPolicyManager的构造函数时会解析音频策略配置文件:audio_policy_configuration.xml,得到大部分音频策略信息,其中包括硬件模块、输入/输出设备及音量曲线等,这些信息会被保存在AudioPolicyConfig中
关键类及说明:
类名 | 作用 |
---|---|
AudioPolicyConfig | 保存音频策略信息,包括硬件模块,输入/输出设备,音量曲线等 |
IVolumeCurvesCollection | 音频曲线类的基类,规定了音频曲线类需要实现的一些基本方法 |
VolumeCurvesCollection | 音频曲线功能的实现者,继承了KeyedVector,保存audio_stream_type_t和VolumeCurvesForStream的对应关系 |
VolumeCurvesForStream | 继承了KeyedVector,保存device_category和VolumeCurve的对应关系 |
VolumeCurve | 用于描述解析出的音频曲线的具体数值 |
在AudioPolicyManager.cpp的构造函数中会执行两个方法:
AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
: AudioPolicyManager(clientInterface, false /*forTesting*/)
{
loadConfig();
initialize();
}
其中loadConfig方法会先判断宏USE_XML_AUDIO_POLICY_CONF
的值,如果这个宏被定义则说明要从音频策略配置文件读取音频策略信息(基本都会定义),之后便会去解析配置文件audio_policy_configuration.xml:
void AudioPolicyManager::loadConfig() {
#ifdef USE_XML_AUDIO_POLICY_CONF
if (deserializeAudioPolicyXmlConfig(getConfig()) != NO_ERROR) {
#else
if ((ConfigParsingUtils::loadConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE, getConfig()) != NO_ERROR)
&& (ConfigParsingUtils::loadConfig(AUDIO_POLICY_CONFIG_FILE, getConfig()) != NO_ERROR)) {
#endif
ALOGE("could not load audio policy configuration file, setting defaults");
getConfig().setDefault();
}
}
调用deserializeAudioPolicyXmlConfig(getConfig())
方法去解析配置文件时,使用getConfig()方法传入一个参数,这个参数的类型是AudioPolicyConfig
在AudioPolicyConfig.h中:
class AudioPolicyConfig
{
public:
AudioPolicyConfig(HwModuleCollection &hwModules,
DeviceVector &availableOutputDevices,
DeviceVector &availableInputDevices,
sp<DeviceDescriptor> &defaultOutputDevices,
VolumeCurvesCollection *volumes = nullptr)
: mHwModules(hwModules),
mAvailableOutputDevices(availableOutputDevices),
mAvailableInputDevices(availableInputDevices),
mDefaultOutputDevices(defaultOutputDevices),
mVolumeCurves(volumes),
mIsSpeakerDrcEnabled(false)
......
可以看到AudioPolicyConfig类中包含了很多信息,其中mVolumeCurves就是音频曲线
接着看deserializeAudioPolicyXmlConfig
方法的实现:
#ifdef USE_XML_AUDIO_POLICY_CONF
// Treblized audio policy xml config will be located in /odm/etc or /vendor/etc.
static const char *kConfigLocationList[] =
{
"/odm/etc", "/vendor/etc", "/system/etc"};
static const int kConfigLocationListSize =
(sizeof(kConfigLocationList) / sizeof(kConfigLocationList[0]));
static status_t deserializeAudioPolicyXmlConfig(AudioPolicyConfig &config) {
char audioPolicyXmlConfigFile[AUDIO_POLICY_XML_CONFIG_FILE_PATH_MAX_LENGTH];
std::vector<const char*> fileNames;
status_t ret;
if (property_get_bool("ro.bluetooth.a2dp_offload.supported", false) &&
property_get_bool("persist.bluetooth.a2dp_offload.disabled", false)) {
// A2DP offload supported but disabled: try to use special XML file
fileNames.push_back(AUDIO_POLICY_A2DP_OFFLOAD_DISABLED_XML_CONFIG_FILE_NAME);
}
fileNames.push_back(AUDIO_POLICY_XML_CONFIG_FILE_NAME);
for (const char* fileName : fileNames) {
for (int i = 0; i < kConfigLocationListSize; i++) {
PolicySerializer serializer;
snprintf(audioPolicyXmlConfigFile, sizeof(audioPolicyXmlConfigFile),
"%s/%s", kConfigLocationList[i], fileName);
ret = serializer.deserialize(audioPolicyXmlConfigFile, config);
if (ret == NO_ERROR) {
return ret;
}
}
}
return ret;
}
#endif
这段代码做了一个循环,解析了”/odm/etc”, “/vendor/etc”, “/system/etc”这三个路径和AUDIO_POLICY_XML_CONFIG_FILE_NAME拼接的文件,而AUDIO_POLICY_XML_CONFIG_FILE_NAME就是audio_policy_configuration.xml
#define AUDIO_POLICY_XML_CONFIG_FILE_NAME "audio_policy_configuration.xml"
在audio_policy_configuration.xml中,通过include的方式包含了两个xml文件:
......
<!-- Volume section -->
<xi:include href="audio_policy_volumes.xml"/>
<xi:include href="default_volume_tables.xml"/>
......
在audio_policy_volumes.xml中,规定了音频流、输出设备和音量曲线的关系:
因为不同的音频流使用不同的音频曲线,而同一音频流在输出设备不同时也采用不同的音频曲线,所以必须规定这三者的对应关系,xml中的这种对应关系被serializer.deserialize
方法解析后,在代码中体现为VolumeCurvesCollection-VolumeCurvesForStream-VolumeCurve的对应关系
audio_policy_volumes.xml:
<volume stream="音频类型" deviceCategory="输出设备"
ref="音频曲线"/>
<volume stream="AUDIO_STREAM_RING" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
<volume stream="AUDIO_STREAM_RING" deviceCategory="DEVICE_CATEGORY_HEARING_AID"
ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
<volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_HEADSET"
ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
<volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_SPEAKER"
ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE"/>
<volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_EARPIECE"
ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
<volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
......
在default_volume_tables.xml中规定了具体音频曲线的值,如DEFAULT_MEDIA_VOLUME_CURVE
曲线上点的xy值:
......
<reference name="DEFAULT_MEDIA_VOLUME_CURVE">
<!-- Default Media reference Volume Curve -->
<point>1,-5800</point>
<point>20,-4000</point>
<point>60,-1700</point>
<point>100,0</point>
</reference>
<re