前言
我们解析完成car_audio_configuration.xml后,接下来就是动态路由策略的注册,以及多音区的焦点管理,本篇先看下动态路由策略。
正文
CarAudioService启动后,我们先回顾下setupDynamicRoutingLocked这个函数
private void setupDynamicRoutingLocked() {
final AudioPolicy.Builder builder = new AudioPolicy.Builder(mContext);
builder.setLooper(Looper.getMainLooper());
// 加载xml的
loadCarAudioZonesLocked();
for (int i = 0; i < mCarAudioZones.size(); i++) {
CarAudioZone zone = mCarAudioZones.valueAt(i);
// Ensure HAL gets our initial value
//同步当前音量
zone.synchronizeCurrentGainIndex();
Log.v(CarLog.TAG_AUDIO, "Processed audio zone: " + zone);
}
//动态路由策略设置
CarAudioDynamicRouting.setupAudioDynamicRouting(builder, mCarAudioZones);
// Attach the {@link AudioPolicyVolumeCallback}
// 注册volume调节的callback
builder.setAudioPolicyVolumeCallback(mAudioPolicyVolumeCallback);
if (sUseCarAudioFocus) {
// Configure our AudioPolicy to handle focus events.
// This gives us the ability to decide which audio focus requests to accept and bypasses
// the framework ducking logic.
// 初始化CarZonesAudioFocus
mFocusHandler = new CarZonesAudioFocus(mAudioManager,
mContext.getPackageManager(),
mCarAudioZones,
mCarAudioSettings, ENABLE_DELAYED_AUDIO_FOCUS);
builder.setAudioPolicyFocusListener(mFocusHandler);
builder.setIsAudioFocusPolicy(true);
}
mAudioPolicy = builder.build();
if (sUseCarAudioFocus) {
// Connect the AudioPolicy and the focus listener
// 将audiopolicy传递给carAudioFocusZone
mFocusHandler.setOwningPolicy(this, mAudioPolicy);
}
// 动态注册路由策略
int r = mAudioManager.registerAudioPolicy(mAudioPolicy);
if (r != AudioManager.SUCCESS) {
throw new RuntimeException("registerAudioPolicy failed " + r);
}
// 设置 occupan zone info
setupOccupantZoneInfo();
}
我们在Android R- CarAudioService之car_audio_configuration.xml解析中主要说了loadCarAudioZonesLocked过程,今天继续看下setupAudioDynamicRouting和registerAudioPolicy的过程,先看下时序图
好多for循环,一点点来看,先看下setupAudioDynamicRouting,两个参数,一个AudioPolicy的Builder,一个carAudioZones,逻辑不是很复杂,先遍历carAudioZones再遍历tVolumeGroups
static void setupAudioDynamicRouting(AudioPolicy.Builder builder,
SparseArray<CarAudioZone> carAudioZones) {
// 先遍历carAudioZones
for (int i = 0; i < carAudioZones.size(); i++) {
CarAudioZone zone = carAudioZones.valueAt(i);
// 在遍历carAudioZone的VolumeGroups
for (CarVolumeGroup group : zone.getVolumeGroups()) {
// 设置每个group的策略
setupAudioDynamicRoutingForGroup(group, builder);
}
}
}
我们在解析car_audio_configuration.xml的时候,知道有多个zone,每个zone有有多个group。每个group下有多个device,每个device下又有多个context,这个函数就是遍历每个group下的这些device和context内容。
private static void setupAudioDynamicRoutingForGroup(CarVolumeGroup group,
AudioPolicy.Builder builder) {
// Note that one can not register audio mix for same bus more than once.
// 遍历当前group下的address
for (String address : group.getAddresses()) {
boolean hasContext = false;
// 根据group下的address 拿到对应的CarAudioDeviceInfo
CarAudioDeviceInfo info = group.getCarAudioDeviceInfoForAddress(address);
// 将CarAudioDeviceInfo的信息赋值给到AudioFormat
AudioFormat mixFormat = new AudioFormat.Builder()
.setSampleRate(info.getSampleRate())
.setEncoding(info.getEncodingFormat())
.setChannelMask(info.getChannelCount())
.build();
AudioMixingRule.Builder mixingRuleBuilder = new AudioMixingRule.Builder();
// 遍历address下的context
for (int carAudioContext : group.getContextsForAddress(address)) {
hasContext = true;
// 每个carAudioContext都会对应多个AudioAttribute的usage,根据carAudioContext得到AudioAttributes usage的数组
int[] usages = CarAudioContext.getUsagesForContext(carAudioContext);
// 遍历AudioAttributes的usages
for (int usage : usages) {
// 构建attributes
AudioAttributes attributes = buildAttributesWithUsage(usage);
mixingRuleBuilder.addRule(attributes,
AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE);
}
if (Log.isLoggable(CarLog.TAG_AUDIO, Log.DEBUG)) {
Log.d(CarLog.TAG_AUDIO, String.format(
"Address: %s AudioContext: %s sampleRate: %d channels: %d usages: %s",
address, carAudioContext, info.getSampleRate(), info.getChannelCount(),
Arrays.toString(usages)));
}
}
if (hasContext) {
// It's a valid case that an audio output address 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.
//mixingRuleBuilder 赋值给AudioMix 并且构建AudioMix
AudioMix audioMix = new AudioMix.Builder(mixingRuleBuilder.build())
.setFormat(mixFormat)
.setDevice(info.getAudioDeviceInfo())
.setRouteFlags(AudioMix.ROUTE_FLAG_RENDER)
.build();
// 将AudioMix add 到 AudioPolicy中
builder.addMix(audioMix);
}
}
}
这个函数就是动态路由的核心了,解析每个group下的device信息以及device下的context信息,context真正对应的是AudioAttributes的usage数组(一个context对应一个usage数组),目前这个context除了关联AudioAttributes的usage之外,还有一点权限的check,在未发现,谷歌如此设计的寓意何为。这样就等于一个device对应多个usage数组。将一个device和多个usage数组组成一个audioMix 。也就是一个音频数据通路。当我们使用同一通路上这些AudioAttributes的usage进行播放时,声音都选择同一个AudioPolicy的策略上了。如下总结了Android AOSP代码中 bus与AudioAttributes的tree目录
下一篇分析registerAudioPolicy的过程。