背景:
在音频子系统课程中讲解过AudioTrack获取对应播放Device,常规情况都在
frameworks/av/services/audiopolicy/enginedefault/src/Engine.cpp
代码中的getDevicesForStrategyInt方法中进行匹配判断获取。
这种设备路由方式选着device,其实对于正常手机等普通使用来说也是完全够用的。但是明显也发现出它的明显缺点,就是对于设备路由方式都是靠代码静态编码确定的,要修改的话只能靠修改Engine.cpp的源码才可以完成,灵活性太差,不容易扩展。
随着车机设备的引入及手机需求的不断增加,安卓就新引入了AudioPolicy来实现动态路由策略,
本文将重点介绍AudioPolicy这部分内容。
剖析java层面的AudioPolicy,AudioMix,AudioMixingRule
AudioPolicy一般主要是用于动态设备路由策略,从传统默认的代码写死固定策略中有了一个很好的动态扩展,大大增加了音频设备灵活选择。
AudioPolicy是设备路由策略的扩展接口,当有人创建了AudioPolicy对象,并注册给AudioPolicyService时,AudioPolicyService就会优先使用这个路由策略,而不会使用默认的硬编码策略。
AudioPolicy相关的源码是在/frameworks/base/media/java/android/media/audiopolicy/目录中。

这里主要研究一下AudioPolicy,AudioPolicyConfig,AudioMix,AudioMixingRule。
本想寻找关于这个的AudioPolicy等官方文档解释,但是代码注释中也没有啥解释,半天没找到,最后通过git进行查找,最后确实查找到了一个官方权威解释。
Author: Jean-Michel Trivi <jmtrivi@google.com>
Date: Tue Jul 1 09:48:46 2014 -0700
Define audio policy, mixes, and mixing rules
An AudioMixingRule is a collection of AudioAttributes and match/exclude
rules.
An AudioMix is defined by its AudioMixingRule, AudioFormat and
routing flag.
An AudioPolicyConfig is a collection of AudioMix and is
parcellable.
An AudioPolicy has an AudioPolicyConfig, and
can be registered/unregistered through AudioManager.
bug 16009464
补充上面没说到的AudioPolicy类的作用,主要是提供对音频路由和音频焦点的访问管理权限。
/**
* @hide
* AudioPolicy provides access to the management of audio routing and audio focus.
*/
@SystemApi
public class AudioPolicy {
这几个类的关系,这里找到了一个非常好网络图片:

上面是AudioPolicy在Java层中的数据结构类图。所有的数据结构都保存在AudioPolicyConfig对象中,一个AudioPolicyConfig对象代表一个播放路由定制策略。
在AudioPolicyConfig对象中,会包含多个AudioMix对象。每个AudioMix对象代表的是一个播放设备的选择策略。所以,每个AudioMix对象只包含一个DeviceAddress的字符串。
每个播放Device对应一个匹配策略对象–AudioMixingRule,在AudioMixingRule中,可以包含多条匹配规则–AudioMixingRule.AudioMixMatchCriterion对象。
目前系统中支持的种类:
/**
* A rule requiring the usage information of the {@link AudioAttributes} to match.
* This mixing rule can be added with {@link Builder#addRule(AudioAttributes, int)} or
* {@link Builder#addMixRule(int, Object)} where the Object parameter is an instance of
* {@link AudioAttributes}.
*/
public static final int RULE_MATCH_ATTRIBUTE_USAGE = 0x1;
/**
* A rule requiring the capture preset information of the {@link AudioAttributes} to match.
* This mixing rule can be added with {@link Builder#addRule(AudioAttributes, int)} or
* {@link Builder#addMixRule(int, Object)} where the Object parameter is an instance of
* {@link AudioAttributes}.
*/
public static final int RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET = 0x1 << 1;
/**
* A rule requiring the UID of the audio stream to match that specified.
* This mixing rule can be added with {@link Builder#addMixRule(int, Object)} where the Object
* parameter is an instance of {@link java.lang.Integer}.
*/
public static final int RULE_MATCH_UID = 0x1 << 2;
/**
* A rule requiring the userId of the audio stream to match that specified.
* This mixing rule can be added with {@link Builder#addMixRule(int, Object)} where the Object
* parameter is an instance of {@link java.lang.Integer}.
*/
public static final int RULE_MATCH_USERID = 0x1 << 3;
/**
* A rule requiring the audio session id of the audio stream to match that specified.
* This mixing rule can be added with {@link Builder#addMixRule(int, Object)} where Object
* parameter is an instance of {@link java.lang.Integer}.
* @see android.media.AudioTrack.Builder#setSessionId
*/
public static final int RULE_MATCH_AUDIO_SESSION_ID = 0x1 << 4;
private final static int RULE_EXCLUSION_MASK = 0x8000;
/**
* @hide
* A rule requiring the usage information of the {@link AudioAttributes} to differ.
*/
public static final int RULE_EXCLUDE_ATTRIBUTE_USAGE =
RULE_EXCLUSION_MASK | RULE_MATCH_ATTRIBUTE_USAGE;
/**
* @hide
* A rule requiring the capture preset information of the {@link AudioAttributes} to differ.
*/
public static final int RULE_EXCLUDE_ATTRIBUTE_CAPTURE_PRESET =
RULE_EXCLUSION_MASK | RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET;
/**
* @hide
* A rule requiring the UID information to differ.
*/
public static final int RULE_EXCLUDE_UID =
RULE_EXCLUSION_MASK | RULE_MATCH_UID;
/**
* @hide
* A rule requiring the userId information to differ.
*/
public static final int RULE_EXCLUDE_USERID =
RULE_EXCLUSION_MASK | RULE_MATCH_USERID;
/**
* @hide
* A rule requiring the audio session id information to differ.
*/
public static final int RULE_EXCLUDE_AUDIO_SESSION_ID =
RULE_EXCLUSION_MASK | RULE_MATCH_AUDIO_SESSION_ID;
主要介绍以下几个常用的:
RULE_MATCH_ATTRIBUTE_USAGE:通过AudioAttributes的Usage进行匹配。比如当一个AudioTrack在播放时,指定的Usage是USAGE_MEDIA类型,而Device1也定义了USAGE_MEDIA类型的匹配规则时,AudioPolicyManager就会选择Device1来播放这个AudioTrack的声音。
RULE_EXCLUDE_ATTRIBUTE_USAGE:通过AudioAttributes的Usage进行排除。排除的意思是指Device1不支持USAGE_MEDIA类型的声音播放。
RULE_MATCH_UID:通过APP的UID进行匹配。在Android中,每个3rd APP的UID都不一样。即当指定UID的APP进行声音播放时,AudioPolicyManager就会选择Device1来输出。
RULE_EXCLUDE_UID:通过APP的UID进行排除。意思是Device1不能播放指定UID的APP下发的声音。
RULE_MATCH_USERID:通过UserId进行匹配。上面提到的镜像播放(mirroringDevice)就是通过这个规则来实现的。意思是当指定UserId中的任何APP播放声音时,AudioPolicyManager都会选择Device1来输出。
RULE_EXCLUDE_USERID:通过UserId进行排除。意思是Device1不能播放指定UserId下的所有APP下发的声音。
native层面的AudioPolicy
上面只是AudioPolicy在java层介绍,但是java层面的AudioPolicy只是一些定义构造AudioMix,最后都是会转换成c++类型,而且需要通过跨进程方式传递到audioserver中的AudioPolicyManager中。
一般是系统App定义构造好AudioPolicy即AudioMix对象,然后通过AudioManager接口跨进程到system_server的AudioService,AudioService通过AudioSystem向AudioPolicyManager中注册AudioPolicy数据时,AudioSystem就会将Java层的数据结构转换成C++层的数据结构,注意只需要转换传递核心的AudioMix对象既可以。
转换核心方法:
frameworks/base/core/jni/android_media_AudioSystem.cpp
static jint
android_media_AudioSystem_registerPolicyMixes(JNIEnv *env, jobject clazz,
jobject jMixesList, jboolean registration)
{
//省略
status_t status;
Vector <AudioMix> mixes;
for (jint i = 0; i < numMixes; i++) {
ScopedLocalRef<jobject> jAudioMix(env, env->GetObjectArrayElement(jMixes, i));
if (!env->IsInstanceOf(jAudioMix.get(), gAudioMixClass)) {
return AUDIO_JAVA_BAD_VALUE;
}
AudioMix mix;
//java层面的AudioMix转c++
if (jint jStatus = convertAudioMixToNative(env, &mix, jAudioMix.get());
jStatus != AUDIO_JAVA_SUCCESS) {
return jStatus;
}
mixes.add(mix);
}
ALOGV("AudioSystem::registerPolicyMixes numMixes %d registration %d", numMixes, registration);
status = AudioSystem::registerPolicyMixes(mixes, registration);
ALOGV("AudioSystem::registerPolicyMixes() returned %d", status);
return nativeToJavaStatus(status);
}
看看转换方法convertAudioMixToNative,其实就是对java对象变量读取赋值
static jint convertAudioMixToNative(JNIEnv *env, AudioMix *nAudioMix, const jobject jAudioMix) {
nAudioMix->mMixType = env->GetIntField(jAudioMix, gAudioMixFields.mMixType);
nAudioMix->mRouteFlags = env->GetIntField(jAudioMix, gAudioMixFields.mRouteFlags);
nAudioMix->mDeviceType =
static_cast<audio_devices_t>(env->GetIntField(jAudioMix, gAudioMixFields.mDeviceType));
jstring jDeviceAddress =
static_cast<jstring>(env->GetObjectField(jAudioMix, gAudioMixFields.mDeviceAddress));
const char *nDeviceAddress = env->GetStringUTFChars(jDeviceAddress, NULL);
nAudioMix->mDeviceAddress = String8(nDeviceAddress);
env->ReleaseStringUTFChars(jDeviceAddress, nDeviceAddress);
env->DeleteLocalRef(jDeviceAddress);
nAudioMix->mCbFlags = env->GetIntField(jAudioMix, gAudioMixFields.mCallbackFlags);
jobject jFormat = env->GetObjectField(jAudioMix, gAudioMixFields.mFormat);
javaAudioFormatToNativeAudioConfig(env, &nAudioMix->mFormat, jFormat, false /*isInput*/);
env->DeleteLocalRef(jFormat);
jobject jRule = env->GetObjectField(jAudioMix, gAudioMixFields.mRule);
nAudioMix->mAllowPrivilegedMediaPlaybackCapture =
env->GetBooleanField(jRule, gAudioMixingRuleFields.mAllowPrivilegedPlaybackCapture);
nAudioMix->mVoiceCommunicationCaptureAllowed =
env->GetBooleanField(jRule, gAudioMixingRuleFields.mVoiceCommunicationCaptureAllowed);
jobject jToken = env->GetObjectField(jAudioMix, gAudioMixFields.mToken);
std::unique_ptr<AIBinder, decltype(&AIBinder_decStrong)>
aiBinder(AIBinder_fromJavaBinder(env, jToken), &AIBinder_decStrong);
nAudioMix->mToken = AIBinder_toPlatformBinder(aiBinder.get());
nAudioMix->mVirtualDeviceId = env->GetIntField(jAudioMix, gAudioMixFields.mVirtualDeviceId);
jint status = convertAudioMixingRuleToNative(env, jRule, &(nAudioMix->mCriteria));
env->DeleteLocalRef(jRule);
return status;
}
那么看看AudioMix在c++层面的情况:
frameworks/av/media/libaudioclient/include/media/AudioPolicy.h
class AudioMixMatchCriterion {
public:
AudioMixMatchCriterion() {}
AudioMixMatchCriterion(audio_usage_t usage, audio_source_t source, uint32_t rule);
status_t readFromParcel(Parcel *parcel);
status_t writeToParcel(Parcel *parcel) const;
bool isExcludeCriterion() const;
union {
audio_usage_t mUsage;
audio_source_t mSource;
uid_t mUid;
int mUserId;
audio_session_t mAudioSessionId;
} mValue;
uint32_t mRule;
};
class AudioMix {
};
它们的对应关系是:
C++层的AudioMix对应的是Java层的AudioMix.java。
C++层的AudioMixMatchCriterion对应的是Java层的AudioMixingRule.AudioMixMatchCriterion。
C++层的mDeviceAddress字符串对应的是Java层的mDeviceAddress字符串。
AudioPolicyManager为了将播放Device与outputStream进行关联,定义了AudioPolicyMix类来继承扩展AudioMix类。在AudioPolicyMix类定义了成员变量SwAudioOutputDescriptor mOutput,用于表示此Device关联的outputStream。同时,定义了AudioPolicyMixCollection集合来保存所有的AudioPolicyMix对象。
剩下的AudioPolicyManager中如何使用这个AudioMix进行路由策略选择Device就下一篇文章再看,本文最重要讲解清楚动态路由的java,c++层面的AudioPolicy,AudioMix等类的作业和转换传递到audioserver进程的AudioPolicyManager中。

2527

被折叠的 条评论
为什么被折叠?



