没有合适的资源?快使用搜索试试~ 我知道了~
首页Android 9 Audio系统笔记:音频路由实现——从AudioTrack到audiohal
目录一、动态路由的初始化1、获取路由策略2、向AudioPolicyManager注册路由策略二、动态路由的路由流程,以AudioTrack创建为例创建AudioTrack的路由选择如何定制音频路由1、policy路由配置2、修改AudioControl的sContextToBusMap对应关系小结 上一篇介绍了AudioFlinger的初始化,接下来对音频路由进行介绍。注意,本文主要介绍动态路由,即汽车音频路由的常规方式。针对Android原生路由策略不做深入分析。 什么是音频路由?如何实现音频路由?如何定制音频路由?这是本文要解决的三大问题。 什么是音频路由?音频无非就是把音频数据流放到指
资源详情
资源评论
资源推荐

Android 9 Audio系统笔记:音频路由实现系统笔记:音频路由实现——从从AudioTrack到到audiohal
目录目录一、动态路由的初始化1、获取路由策略2、向AudioPolicyManager注册路由策略二、动态路由的路由流程,以AudioTrack创建为例创建AudioTrack的路由选择如何定制音频路由
1、policy路由配置2、修改AudioControl的sContextToBusMap对应关系小结
上一篇介绍了AudioFlinger的初始化,接下来对音频路由进行介绍。注意,本文主要介绍动态路由,即汽车音频路由的常规方式。针对注意,本文主要介绍动态路由,即汽车音频路由的常规方式。针对Android原生路由策略不做深入分析。原生路由策略不做深入分析。
什么是音频路由?如何实现音频路由?如何定制音频路由?这是本文要解决的三大问题。
什么是音频路由?音频无非就是把音频数据流放到指定的声卡上,然后进行播放。那么,音频路由就是要解决把某种类型的音频流放到那种声卡进行播放的策略。
为什么要这样做?因为现在的Android支持多声卡,并且Android本质有各种类型的音频流。这么多的音频流和声卡需要被有效管理起来,所以需要音频路由来实现。什么是音频流?
这是对上层应用场景的概念,诸如铃声,多媒体音乐,TTS播报等,,某些音频流需要在不同的声卡设备上播放,从而满足不同的需求。你可能会问,手机不就一个喇叭吗,还需要
这么复杂。下面我们来看一个场景,小明插着耳机听着音乐,此时他女朋友小华给他打了个电话。这个时候,铃声声音会同时从耳机和手机喇叭出 来,以保证小明能晓得有来电。如
果单单是从耳机输出,当声音很小的时候那可能会被忽略掉(那可能是要被扒成皮的 乛◡乛 )。这这只是很简单的小场景。
**怎么实现音频路由?**这是本文着重介绍的。下面开始进行介绍。
开始介绍之前,还需重点介绍一下动态路由的初始化,它是汽车路由的核心,所以有必要在开始进行介绍。
一、动态路由的初始化一、动态路由的初始化
CarAudioService的init开始:
//packages/services/Car/service/src/com/android/car/CarAudioService.java
public void init() {
synchronized (mImplLock) {
//mUseDynamicRouting = mContext.getResources().getBoolean(R.bool.audioUseDynamicRouting);
//packages/services/Car/service/res/values/config.xml
//true
if (!mUseDynamicRouting) {
Log.i(CarLog.TAG_AUDIO, "Audio dynamic routing not configured, run in legacy mode"
setupLegacyVolumeChangedListener();
} else {
setupDynamicRouting();
setupVolumeGroups();
setNaviMixChangedListener();
}
}
mUseDynamicRouting变量一般定制会在device overlay目录进行覆盖定制,默认为false,不启用动态路由。我们要使用动态路由,所以这个变量要打开。
private void setupDynamicRouting() {
final IAudioControl audioControl = getAudioControl();
//1、获取路由策略
AudioPolicy audioPolicy = getDynamicAudioPolicy(audioControl);
//2、向AudioPolicyManager注册路由策略
int r = mAudioManager.registerAudioPolicy(audioPolicy);
if (r != AudioManager.SUCCESS) {
throw new RuntimeException("registerAudioPolicy failed " + r);
}
mAudioPolicy = audioPolicy;
}
1、获取路由策略、获取路由策略
//packages/services/Car/service/src/com/android/car/CarAudioService.java
private AudioPolicy getDynamicAudioPolicy(@NonNull IAudioControl audioControl) {
AudioPolicy.Builder builder = new AudioPolicy.Builder(mContext);
builder.setLooper(Looper.getMainLooper());
// 1st, enumerate all output bus device ports ,获取所有的device端口
AudioDeviceInfo[] deviceInfos = mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
//省略一堆
//前方高能,从这里开始进行 context 到 bus的匹配
// 2nd, map context to physical bus
try {
for (int contextNumber : CONTEXT_NUMBERS) {
int busNumber = audioControl.getBusForContext(contextNumber);
mContextToBus.put(contextNumber, busNumber);
CarAudioDeviceInfo info = mCarAudioDeviceInfos.get(busNumber);
if (info == null) {
Log.w(CarLog.TAG_AUDIO, "No bus configured for context: " + contextNumber);
}
}
} catch (RemoteException e) {
Log.e(CarLog.TAG_AUDIO, "Error mapping context to physical bus", e);
}
//建立路由,通过context建立usage到bus的路由建立,核心!
// 3rd, enumerate all physical buses and build the routing policy.
// Note that one can not register audio mix for same bus more than once.
for (int i = 0; i < mCarAudioDeviceInfos.size(); i++) {
int busNumber = mCarAudioDeviceInfos.keyAt(i);
boolean hasContext = false;
CarAudioDeviceInfo info = mCarAudioDeviceInfos.valueAt(i);
AudioFormat mixFormat = new AudioFormat.Builder()
.setSampleRate(info.getSampleRate())
.setEncoding(info.getEncodingFormat())
.setChannelMask(info.getChannelCount())
.build();
AudioMixingRule.Builder mixingRuleBuilder = new AudioMixingRule.Builder();
for (int j = 0; j < mContextToBus.size(); j++) {
if (mContextToBus.valueAt(j) == busNumber) {
hasContext = true;
int contextNumber = mContextToBus.keyAt(j);
//通过context获取对应的usage集合
int[] usages = getUsagesForContext(contextNumber);
for (int usage : usages) {
mixingRuleBuilder.addRule(
new AudioAttributes.Builder().setUsage(usage).build(),
AudioMixingRule.RULE_MATCH_ATTRIBUTE_USAGE);
}
Log.e(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 对象,这个对象包含了所有的usage对应关系和device所需的信息
//就这样建立了一条音频路由策略,当然,现在还没起作用,因为还没注册到动态路由中去
AudioMix audioMix = new AudioMix.Builder(mixingRuleBuilder.build())







安全验证
文档复制为VIP权益,开通VIP直接复制

评论1