Android R- CarAudioService之registerAudioPolicy动态注册(一)

11 篇文章 27 订阅
6 篇文章 15 订阅

前言

我们解析完成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的过程。

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

轻量级LZ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值