前言
1.CarAudioService啟動(dòng)之后調(diào)用init()
2.在init函數(shù)中通過(guò)AudioManager.getDevice獲取了所有的用于輸出的Device,然后把這些device中type是BUS的過(guò)濾出來(lái)
3.然后調(diào)用setupDynamicRouting,這個(gè)方法是設(shè)置動(dòng)態(tài)路由,前面我們分析了setupDynamicRouting的CarAudioZone部分,接下來(lái),我們分析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()
首先看構(gòu)造函數(shù),很簡(jiǎn)單,只是把前面構(gòu)建的carAudioZones保存下來(lái)
private final CarAudioZone[] mCarAudioZones;
CarAudioDynamicRouting(CarAudioZone[] carAudioZones) {
mCarAudioZones = carAudioZones;
}
2. setupAudioDynamicRouting()
我們進(jìn)入dynamicRouting.setupAudioDynamicRouting(builder);來(lái)看看。
兩個(gè)for循環(huán),外層是mCarAudioZones的循環(huán),我們看內(nèi)層循環(huán),在上一章節(jié)中分析道每一個(gè)zone都包含多個(gè)CarVolumeGroup,在這里我們拿AudioPolicy的builder和CarVolumeGroup傳遞給setupAudioDynamicRoutingForGroup(),接下來(lái)我們需要分析setupAudioDynamicRoutingForGroup()
void setupAudioDynamicRouting(AudioPolicy.Builder builder) {
for (CarAudioZone zone : mCarAudioZones) {
for (CarVolumeGroup group : zone.getVolumeGroups()) {
setupAudioDynamicRoutingForGroup(group, builder);
}
}
}
2.1 setupAudioDynamicRoutingForGroup()
最外層是一個(gè)for循環(huán),首先拿到CarVolumeGroup的busNumber,然后根據(jù)busNumber拿到CarAudioDeviceInfo ,拿到CarAudioDeviceInfo 之后,構(gòu)建AudioFormat 和AudioMixingRule,然后進(jìn)入第二層for循環(huán),根據(jù)busNumber拿到 contextNumber,然后根據(jù)contextNumber獲取到usages數(shù)組,拿到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);
}
}
}
我們簡(jiǎn)單總結(jié)一下,首先通過(guò)傳入的mCarAudioZone遍歷其中的每個(gè)CarAudioZone,每個(gè)CarAudioZone又包含一個(gè)CarVolumeGroup的集合,遍歷CarVolumeGroup里面的每個(gè)group,每個(gè)group又包含了一個(gè)device的集合(contextNumber和busNumber組成的map),這樣我們可以通過(guò)busNumber獲取到contextNumber,又可以根據(jù)contextNumber獲取到usages數(shù)組,其實(shí)歸根結(jié)底,我們就是把AudioAttribute的usage數(shù)組和context以及CarAudioDeviceInfo都關(guān)聯(lián)起來(lái)。
AudioMix包含了有usage數(shù)組的mixingRuleBuilder和AudioDeviceInfo,這樣device與usage數(shù)組便對(duì)應(yīng)到一起,在原生的Android里面是通過(guò)stream在AudioPolicyManager的Engine中選擇device,但是Car的這套邏輯是通過(guò)usage和device在上層就配好了,最后addMix就是將audioMix傳遞到AudioPolicy中,然后通過(guò)AudioManager.registerAudioPolicy(mAudioPolicy)注冊(cè)下去。