音量调节接口
我们知道Android Audio的音量调节接口是通过AudioManager的setStreamVolume实现的,这个函数的实现在AudioService的setStreamVolume函数中,然后会调用到setStreamVolumeInt,这个函数首先通过streamState.setIndex发送音量调节的广播通知app更新UI。然后通过消息机制走到setDeviceVolume函数。注:如果要实现硬调音,也就是调节dsp音量不调节安卓音量,可以把config_useFixedVolume这个参数置为true。
我们简单分析一下setDeviceVolume函数
/*package*/ void setDeviceVolume(VolumeStreamState streamState, int device) {
final boolean isAvrcpAbsVolSupported = mDeviceBroker.isAvrcpAbsoluteVolumeSupported();
synchronized (VolumeStreamState.class) {
// Apply volume
streamState.applyDeviceVolume_syncVSS(device, isAvrcpAbsVolSupported);
// Apply change to all streams using this one as alias
int numStreamTypes = AudioSystem.getNumStreamTypes();
for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
if (streamType != streamState.mStreamType &&
mStreamVolumeAlias[streamType] == streamState.mStreamType) {
// Make sure volume is also maxed out on A2DP device for aliased stream
// that may have a different device selected
int streamDevice = getDeviceForStream(streamType);
if ((device != streamDevice) && isAvrcpAbsVolSupported
&& ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
mStreamStates[streamType].applyDeviceVolume_syncVSS(device,
isAvrcpAbsVolSupported);
}
mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice,
isAvrcpAbsVolSupported);
}
}
}
// Post a persist volume msg
sendMsg(mAudioHandler,
MSG_PERSIST_VOLUME,
SENDMSG_QUEUE,
device,
0,
streamState,
PERSIST_DELAY);
}
首先是经过applyDeviceVolume_syncVSS函数走到AudioSystem.cpp的setStreamVolumeInt函数(这个后面再继续分析)。然后发送了一个MSG_PERSIST_VOLUME的消息,通过persistVolume函数把音量值存储到setting数据库中。
native层音量调节的实现
我们上面分析到会走到AudioSystem::setStreamVolumeIndex函数,这个函数通过binder最终走到AudioPolicyManager::setStreamVolumeIndex函数中,然后调用AudioPolicyManager::setVolumeIndexForAttributes函数,在这个函数中Android10.0的代码中已经有了组的概念,我们按照正常的流程往下走,会走到AudioPolicyManagerCustom::checkAndSetVolume函数中,然后这个函数会根据audiopolicy中的audio_policy_volumes.xml文件中配置的声音曲线调用computeVolume计算出一个volumeDb值,然后通过AudioOutputDescriptor::setVolume函数去set音量。这个函数通过setCurVolume函数调用mVolumeActivities[vs].setVolume(volumeDb),这个mVolumeActivities就是当前在这个output中活动的track,所以我们跟到了AudioTrack::setVolume函数,这个函数会调用mProxy->setVolumeLR函数
void setVolumeLR(gain_minifloat_packed_t volumeLR) {
mCblk->mVolumeLR = volumeLR;
}
通过上面的代码我们知道就是把现在的增益保存在mCblk->mVolumeLR中,看到mCblk我们就应该能联想到这是与audioflinger通信的环形buffer,所以使用这个音量的地方肯定在AudioFlinger中,我们去AudioFlinger中去找发现是prepareTracks_l函数通过proxy->getVolumeLR拿到的这个增益。我们知道AudioFlinger的threadLoop函数会不断的循环的调用prepareTracks_l函数去准备音频流和混音流的数据,在这里把audiopolicy设置的音量以及track的音量和master音量做一个计算(一般是相乘),所以现在AudioFlinger拿到的pcm数据就已经包含了修改的增益,然后通过threadLoop_wrtie函数把修改了增益的pcm数据写到hal层,到这里整个setStreamVolume的流程就分析完成了。
例:app1:混音数据1 = 音频数据1 * master_volume * stream1_volume * AudioTrack1_volume
app2:混音数据2 = 音频数据2 * master_volume * stream2_volume * AudioTrack2_volume
然而在车机上会有主副屏后排屏的概念,这时候我们可以使用CarAudioManager的setGroupVolume去set音量。
setGroupVolume的实现
setGroupVolume会走到setCurrentGainIndex函数然后把音量值存储到setting数据库中,然后会走到AudioManager的setAudioPortGain函数中
public static int setAudioPortGain(AudioPort port, AudioGainConfig gain) {
if (port == null || gain == null) {
return ERROR_BAD_VALUE;
}
AudioPortConfig activeConfig = port.activeConfig();
AudioPortConfig config = new AudioPortConfig(port, activeConfig.samplingRate(),
activeConfig.channelMask(), activeConfig.format(), gain);
config.mConfigMask = AudioPortConfig.GAIN;
return AudioSystem.setAudioPortConfig(config);
}
这个函数会把增益等一些参数封装到AudioPortConfig中然后调用AudioSystem.setAudioPortConfig函数,经过一系列的调用会走到AudioPolicyManager::setAudioPortConfig函数,然后通过binder等一系列封装调用会走到AudioFlinger::setAudioPortConfig函数中,最终会走到hal层audio_hw的adev_set_audio_port_config函数中去,最后的实现在auto_hal.c的auto_hal_set_audio_port_config函数中,最终会调用到kernel的set_volume函数中去。这样看来这条通路设置的应该就是dsp的音量,因为并没有修改到AudioFlinger中pcm数据的增益,这个函数留到后面仔细分析。