Android 10.0 CarAudioService(二)
前言
1.CarAudioService启动之后调用init()
2.在init函数中通过AudioManager.getDevice获取了所有的用于输出的Device,然后把这些device中type是BUS的过滤出来
3.然后调用setupDynamicRouting,这个方法是设置动态路由,前面我们分析了setupDynamicRouting的CarAudioZone部分,接下来,我们分析CarAudioDynamicRouting()
// Setup dynamic routing rules by usage
final CarAudioDynamicRouting dynamicRouting = new CarAudioDynamicRouting(mCarAudioZones);
dynamicRouting.setupAudioDynamicRouting(builder);
// Attach the {@link AudioPolicyVolumeCallback}
builder.setAudioPolicyVolumeCallback(mAudioPolicyVolumeCallback);
1. CarAudioDynamicRouting()
首先看构造函数,很简单,只是把前面构建的carAudioZones保存下来
private final CarAudioZone[] mCarAudioZones;
CarAudioDynamicRouting(CarAudioZone[] carAudioZones) {
mCarAudioZones = carAudioZones;
}
2. setupAudioDynamicRouting()
我们进入dynamicRouting.setupAudioDynamicRouting(builder);来看看。
两个for循环,外层是mCarAudioZones的循环,我们看内层循环,在上一章节中分析道每一个zone都包含多个CarVolumeGroup,在这里我们拿AudioPolicy的builder和CarVolumeGroup传递给setupAudioDynamicRoutingForGroup(),接下来我们需要分析setupAudioDynamicRoutingForGroup()
void setupAudioDynamicRouting(AudioPolicy.Builder builder) {
for (CarAudioZone zone : mCarAudioZones) {
for (CarVolumeGroup group : zone.getVolumeGroups()) {
setupAudioDynamicRoutingForGroup(group, builder);
}
}
}
2.1 setupAudioDynamicRoutingForGroup()
最外层是一个for循环,首先拿到CarVolumeGroup的busNumber,然后根据busNumber拿到CarAudioDeviceInfo ,拿到CarAudioDeviceInfo 之后,构建AudioFormat 和AudioMixingRule,然后进入第二层for循环,根据busNumber拿到 contextNumber,然后根据contextNumber获取到usages数组,拿到usage之后,便可以mixingRuleBuilder.addRule()
/**
* Enumerates all physical buses in a given volume group and attach the mixing rules.
* @param group {@link CarVolumeGroup} instance to enumerate the buses with
* @param builder {@link AudioPolicy.Builder} to attach the mixing rules
*/
private void setupAudioDynamicRoutingForGroup(CarVolumeGroup group,
AudioPolicy.Builder builder) {
// Note that one can not register audio mix for same bus more than once.
for (int busNumber : group.getBusNumbers()) {
boolean hasContext = false;
CarAudioDeviceInfo info = group.getCarAudioDeviceInfoForBus(busNumber);
AudioFormat mixFormat = new AudioFormat.Builder()
.setSampleRate(info.getSampleRate())
.setEncoding(info.getEncodingFormat())
.setChannelMask(info.getChannelCount())
.build();
AudioMixingRule.Builder mixingRuleBuilder = new AudioMixingRule.Builder();
for (int contextNumber : group.getContextsForBus(busNumber)) {
hasContext = true;
int[] usages = getUsagesForContext(contextNumber);
for (int usage : usages) {
mixingRuleBuilder.addRule(
new AudioAttributes.Builder().setUsage(usage).build(),
AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE);
}
Log.d(CarLog.TAG_AUDIO, "Bus number: " + busNumber
+ " contextNumber: " + contextNumber
+ " sampleRate: " + info.getSampleRate()
+ " channels: " + info.getChannelCount()
+ " usages: " + Arrays.toString(usages));
}
if (hasContext) {
// It's a valid case that an audio output bus is defined in
// audio_policy_configuration and no context is assigned to it.
// In such case, do not build a policy mix with zero rules.
AudioMix audioMix = new AudioMix.Builder(mixingRuleBuilder.build())
.setFormat(mixFormat)
.setDevice(info.getAudioDeviceInfo())
.setRouteFlags(AudioMix.ROUTE_FLAG_RENDER)
.build();
builder.addMix(audioMix);
}
}
}
我们简单总结一下,首先通过传入的mCarAudioZone遍历其中的每个CarAudioZone,每个CarAudioZone又包含一个CarVolumeGroup的集合,遍历CarVolumeGroup里面的每个group,每个group又包含了一个device的集合(contextNumber和busNumber组成的map),这样我们可以通过busNumber获取到contextNumber,又可以根据contextNumber获取到usages数组,其实归根结底,我们就是把AudioAttribute的usage数组和context以及CarAudioDeviceInfo都关联起来。
AudioMix包含了有usage数组的mixingRuleBuilder和AudioDeviceInfo,这样device与usage数组便对应到一起,在原生的Android里面是通过stream在AudioPolicyManager的Engine中选择device,但是Car的这套逻辑是通过usage和device在上层就配好了,最后addMix就是将audioMix传递到AudioPolicy中,然后通过AudioManager.registerAudioPolicy(mAudioPolicy)注册下去。