前言

Android 在O之后增加了CarAudio,增加了多音区,增加了动态路由,而对于Audio的三大块AudioTrack、AudioFlinger和AudioPolicy。CarAudio主要解决了车载上的AudioPolicy策略。我们之前分析了car_audio_configuration.xml的解析,以及解析后如何构建路由策略和多音区的AudioFocus,今天继续分析。解析后的路由策略是如何注册到AudioPlolicy中,以及如何应用在我们系统中的。

正文

在整个CarAudio启动时,核心初始化的就是setupDynamicRouting()函数,我们七七八八也分析的差不多了,最后分析下解析完的xml,做好的路由策略是如何注册下去的,还是先看下时序图,首先是构建AudioPolcy的时序:

我们直接进CarAudioDynamicRouting里看下:

    static void setupAudioDynamicRouting(AudioPolicy.Builder builder,            SparseArray<CarAudioZone> carAudioZones) {             for (int i = 0; i < carAudioZones.size(); i++) {                 CarAudioZone zone = carAudioZones.valueAt(i);            for (CarVolumeGroup group : zone.getVolumeGroups()) {                     setupAudioDynamicRoutingForGroup(group, builder);            }        }    }

这个函数没啥说的,比较简单,我们举例来说明下吧,在Android R- CarAudioService之registerAudioPolicy动态注册(一)中,我们知道有carAudioZones有3个,这里以primary zone举例,他有四个group。继续看下setupAudioDynamicRoutingForGroup

    private static void setupAudioDynamicRoutingForGroup(CarVolumeGroup group,            AudioPolicy.Builder builder) {             // Note that one can not register audio mix for same bus more than once.        for (String address : group.getAddresses()) {                 boolean hasContext = false;            CarAudioDeviceInfo info = group.getCarAudioDeviceInfoForAddress(address);            AudioFormat mixFormat = new AudioFormat.Builder()                    .setSampleRate(info.getSampleRate())                    .setEncoding(info.getEncodingFormat())                    .setChannelMask(info.getChannelCount())                    .build();            AudioMixingRule.Builder mixingRuleBuilder = new AudioMixingRule.Builder();            for (int carAudioContext : group.getContextsForAddress(address)) {                     hasContext = true;                int[] usages = CarAudioContext.getUsagesForContext(carAudioContext);                for (int usage : usages) {                         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.                AudioMix audioMix = new AudioMix.Builder(mixingRuleBuilder.build())                        .setFormat(mixFormat)                        .setDevice(info.getAudioDeviceInfo())                        .setRouteFlags(AudioMix.ROUTE_FLAG_RENDER)                        .build();                builder.addMix(audioMix);            }        }    }

代码比较长,但很重要,先看第一个for循环即 (String address : group.getAddresses()) ,我们知道每个group都会至少有一个bus,每个bus都会有一个addrss。比如还是在Android R- CarAudioService之registerAudioPolicy动态注册(一)中我们的primary zone中group0中有bus0、bus3、bus6和bus7,group1中有bus1和bus2,group2中有bus4,group3中有bus5.这里取出每个bus中一些配置信息,这些bus的信息是来自audio_policy_configuration.xml中的,截取一段bus0的如下:

            <devicePorts>                <devicePort tagName="bus0_media_out" role="sink" type="AUDIO_DEVICE_OUT_BUS"                        address="bus0_media_out">                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"                            samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>                    <gains>                        <gain name="" mode="AUDIO_GAIN_MODE_JOINT"                                minValueMB="-3200" maxValueMB="600" defaultValueMB="0" stepValueMB="100"/>                    gains>                devicePort>

然后构建AudioFormat的SampleRate、Encoding、ChannelMask,如上图就是48000、AUDIO_FORMAT_PCM_16_BIT、和AUDIO_CHANNEL_OUT_STEREO。
接下来又是一个for循环,因为每个bus下都至少有一个carAudioContext ,例如primary zone中的bus0下有个carAudioContext Music,而rear seat zone1和 rear seat zone2中每个bus下都是很多context的。这里的第二个for循环就是遍历每个bus下的carAudioContext ,为什么要遍历carAudioContext呢?其实最主要的就是找AudioAttributes的Usage,我们在Android8.0之前的版本AudioPolicyManager的路由策略都是根据播放AudioTrack或者MediaPlayer的StreamType来处理的。但是CarAudio的动态路由是根据Usage来处理的。还是看下在Android R- CarAudioService之registerAudioPolicy动态注册(一)中,每个carAudioContext下都有至少1个usage,这里就是要找出所有的usage。然后加到AudioMixingRule中,addRule的过程就不说了,他们最终都被放到AudioMixMatchCriterion集合中了,AudioMixMatchCriterion有3个属性其中Rule是RULE_MATCH_ATTRIBUTE_USAGE,IntProp是 Integer.MIN_VALUE,以及传入的AudioAttributes,还有他们的mTargetMixType 是AudioMix.MIX_TYPE_PLAYERS
最后把这个 AudioMixingRule添加到AudioMix中,具体代码也不细说了,再记住一个属性mRouteFlags是AudioMix.ROUTE_FLAG_RENDER 。这些后面会用到。

总结

到这里我们来总结下,解析完成XMl后便进入到 CarAudioDynamicRouting中来构建动态路由策略,大体步骤如下:
1.循环处理Zones下的每个zone
1.1循环处理zone下的每个volumegroup
1.1.1循环处理volumegroup下的每个bus,同时每个bus对应创建了一个AudioMixingRule
1.1.1.1循环处理bus下的每个caraudiocontext
1.1.1.1.1循环处理caraudiocontext下的每个usage
1.1.1.1.1.1将bus下的每个caraudiocontext以及每个caraudiocontext下usage全部加入到AudioMixingRule中,感觉有点绕,其实我也没有get到谷歌搞caraudiocontext的用意,感觉很啰嗦,这个简单说就是把bus下所有的usage全部加到AudioMixingRule中。
1.1.1.2将每个bus的device信息加上AudioMixingRule 然后创建一个AudioMix,这个AudioMix化繁入简,说白了就是一个device对应了一群usage,多少有点路由的概念了。
1.1.1.3最后将AudioMix加到AudioPolicy中。

由于谷歌把CarAudioVolume、CarAudioZone、以及CarAudioFocus都融合到一起了,所以这块看起来有点乱,尤其一个接一个的for循环。
归根结底就是将bus和usage对应上(1个bus对应一群usage),不同的bus可以有相同的usage,但前提相同usage对应的bus一定是不同zone的。这个后面说同一个应用如何播放到不同音区上时再说。

所以我们在做定制路由策略的时候,一定要考虑好,哪些Usage放到同一个bus上。哪些bus放到同一个group中。

下一篇继续说如何将添加到AudioPolicy中的路由策略注册到FW的AudioPolicyManager中的。

更多相关文章

  1. Android主线程消息循环
  2. Android中的多线程之handler
  3. React Native Linking与 Android原生页面路由跳转问题
  4. Android:使用VideoView(TV显示屏待机状态,循环播放演示视频)
  5. android 加载进度条动画
  6. android 操作路由表
  7. 转Android(安卓)安全攻防(二): SEAndroid(安卓)bionic
  8. android 线程间通信
  9. android中无限循环滑动的gallery实例

随机推荐

  1. 转:Android中shape的使用
  2. Android自定义实现圆形播放进度条
  3. adb 无线调试
  4. Android系列开发博客资源汇总
  5. 浣跨敤 Android(安卓)瀹炵幇鑱旂綉
  6. Android框架模式之-MVP简单使用
  7. Android(安卓)Studio常用快捷键、Android
  8. Android中LocationManager的简单使用,获
  9. Android的广播机制——Broadcast Reciver
  10. Android适配(屏幕适配、国际化适配)