音频策略的构建
1、概述
2、AudiopolicyService
2.1 任务
2.2 启动流程
2.2.1 加载audio_policy.conf(xml)配置文件
2.2.2 初始化各种音频流对应的音量调节点
2.2.3 加载audio policy硬件抽象库
2.2.4设置输出设备
ps:audiopatch流程简介
2.2.5打开输出设备
2.3 策略制定总结
3、AudioFlinger
3.1 任务
3.2 启动流程
3.3 打开output
4、总结
1、概述
本文讲解音频系统的“核心组成:音频策略的制定者AudiopolicyService以及音频策略的执行者AudioFlinger。其它的文章深度都不高,而且独立性较强,分别讲解audiofligner和audiopolicyservice服务能够独立完成的业务功能,本篇重点讲解audioflinger和audiopolicyservice如何协同工作以及分工,共同保障音频系统的正常工作。
其中 AudioPolicy 相当于军师的角色,专门来制定 Audio 播放时的相关的策略及设定相关的参数,而 AudioFlinger 相当于将军,会根据军师的策略来执行。
上面的话只要是学过音频相关知识的人都会说,都了解的。***那么什么是策略呢?什么是执行呢?策略和执行能放到一起吗?策略和执行的隔离程度是什么级别的?***把这个问题想清楚,你的思维就比别人跟进一步。
***策略就是组织各种数据的关系,定义整体的结构,制定事务的流程。***而执行则是处理具体的事务,负责流程中某个具体的步骤,管理某个数据。
策略和执行从代码的角度来看完全可以放在一起。但是根据我们开发的经验可以知道,策略的修改频率要远高于执行。如果我们把策略和执行放到一个库里面,那么每次修改策略都会对执行引入风险。所以我们要将策略和执行分开。这也是软件设计思想,分离变化的一种体现。
策略和执行(policy和finger)的隔离程度是库隔离,但是还是运行在一个进程。如果其中一个模块发生崩溃还是会连累另外一个模块。
隔离程度简单划分有三种类隔离,库隔离,进程隔离。
2、AudiopolicyService
2.1 任务
管理输入输出设备,包括设备的断连,设备的选择和切换等(加载audio_policy.default.so库得到audio_policy_module模块)
管理系统的音频策略,比如通话时播放音乐、或者播放音乐时来电的一系列处理(通过audio_policy_module模块打开audio_policy_device设备)
管理系统的音量
上层的一些音频参数也可以通过AudioPolicyService设置到底层去 (通过audio_policy_device
设备创建audio_policy)
2.2 启动流程
AudioPolicyService服务运行在audioserver进程中, 随着audioserver进程启动而启动。
//frameworks/av/media/audioserver/main_audioserver.cpp
int main(int argc __unused, char **argv)
......
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
ALOGI("ServiceManager: %p", sm.get());
AudioFlinger::instantiate();//实例化AudioFlinger服务
AudioPolicyService::instantiate();//实例化AudioPlicyService服务
其中,AudioPolicyService::instantiate()并不由AudioPolicyService实现,而是BinderService类的一个实现。包括AudioFlinger,AudioPolicyservice等在内的几个服务都继承自这个统一的Binder的服务类,具体实现在BinderService.h中。如果后续我们需要自己开发一个基于binder的服务那么也可以继承binderservice来实现。
/frameworks/native/include/binder
static status_t publish(bool allowIsolated = false,
int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT) {
sp<IServiceManager> sm(defaultServiceManager());
//SERVICE是文件中定义的一个模板,AudioPolicyService调用了instantiate()函数,
//所以当前的SERVICE为AudioPolicyService
return sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated,
dumpFlags);
publish()函数获取到ServiceManager的代理,然后new一个调用instantiate的service对象并把它添加到ServiceManager中。所以下一步就是去分析AudioPolicyService的构造函数。
// frameworks/av/services/audiopolicy/service/AudioPolicyService.cpp
AudioPolicyService::AudioPolicyService()
: BnAudioPolicyService(),
mAudioPolicyManager(NULL),
mAudioPolicyClient(NULL),
mPhoneState(AUDIO_MODE_INVALID),
mCaptureStateNotifier(false) {
}
它的构造函数里面初始化了一些变量,那么AudioPolicyService所作的初始化的事情是在什么地方进行的呢,继续分析上面的构造函数,AudioPolicyService是继承自BnAudioPolicyService的,一步步往上推,最终发现它的祖先是RefBase,根据强指针的特性,目标对象在第一次被引用时会调用onFirstRef()的,我们就去看一下AudioPolicyService::onFirstRef()。不难发现,android代码中的构造函数一般都用于初始化一些成员变量。大部分的工作都是在其它函数中实现。比如onfirstref。
void AudioPolicyService::onFirstRef()
{
{
Mutex::Autolock _l(mLock);
// start audio commands thread
mAudioCommandThread = new AudioCommandThread(String8("ApmAudio"), this);//创建ApmAudio线程用于执行
audio命令
// start output activity command thread
mOutputCommandThread = new AudioCommandThread(String8("ApmOutput"), this);//创建ApmOutpur线程用于执行
输出命令
mAudioPolicyClient = new AudioPolicyClient(this);//实例化AudioPolicyClient对象
mAudioPolicyManager = createAudioPolicyManager(mAudioPolicyClient);//实例化AudioPolicyManager对象
}
......
// load audio processing modules
//解析audio_effects.conf 文件,得到并加载系统支持的音效库。初始化各个音效对应的参数,将各音效和对应的输入和输出
//流绑定在一起,这样,当上层要使用音效时,就会在对应的threadloop中调用process_l音效处理函数。
sp<AudioPolicyEffects> audioPolicyEffects = new AudioPolicyEffects();//初始化音效相关
#ifdef SPRD_CUSTOM_AUDIO_POLICY
{
Mutex::Autolock _l(mLock);
mAudioPolicyEffects = audioPolicyEffects;//
}
pthread_t uidpolicy;
这里audiopolicyservice为什么要起两个commandthread?audioflinger和audiopoliyservice是在同一个进程。如果audiopolicymanager直接调用audioflinger的接口就会阻塞住。(也就是同步的)。而通过线程去调用audioflinger的话或者处理一些耗时的任务,audiopolicymanager就可以很快返回不需要阻塞住。我自己的看法如果没了这两个thread。audiopolicyservice都不能叫service了,直接和manager合二为一算了
AudioPolicyClient,AudioPolicyClient类定义在AudioPolicyService.h中
//frameworks/av/services/audiopolicy/service/AudioPolicyService.h
class AudioPolicyClient : public AudioPolicyClientInterface
{
public:
explicit AudioPolicyClient(AudioPolicyService *service) : mAudioPolicyService(service) {}
......
}
它的实现在frameworks/av/services/audiopolicy/service/AudioPolicyClientImpl.cpp中。创建完AudioPolicyClient之后通过调用createAudioPolicyManager方法创建了一个AudioPolicyManager对象,下面看一下createAudioPolicyManager方法中是怎样创建
AudioPolicyManager的。
//frameworks/av/services/audiopolicy/manager/AudioPolicyFactory.cpp
extern "C" AudioPolicyInterface* createAudioPolicyManager(
AudioPolicyClientInterface *clientInterface)
{
return new AudioPolicyManager(clientInterface);//将会调用类AudioPolicyManager的构造函数,接下来将重点分析该构
造函数,这是我们分析AudioPolicyService的关键。
}
可见他是直接new了一个AudioPolicyManager然后把刚才创建的AudioPolicyClient传了进去,使用AudioPolicyClientInterface对象来构造AudioPolicyManager对象,AudioPolicyManager继承于AudioPolicyInterface
AudioPolicyManager
直接看其构造函数:最新的android版本应该是在onfirstref函数
//frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface) :
......
{
//1.加载解析配置文件
//配置文件路径:/vendor/etc/ 或者 /system/etc/
ConfigParsingUtils::loadConfig(....);
//2.初始化各种音频流对应的音量调节点
checkAndSetVolume;setVolumeCurveInsdex
//3.加载audio policy硬件抽象库即根据名字加载mHwmodule对应的so文件,该文件由参加提供
hwModule->setHandle(mpClientInterface->loadHwModule(hwModule->getName()));
//4.打开output输出设备,同时会创建playbackthread,其会得到一个output整数(该函数的参数),这个整数会对应播放线程,
也可以对应SwAudioOutputDescriptor*/
status_t status = mpClientInterface->openOutput(outProfile-
>getModuleHandle(),&output,&config,&outputDesc->mDevice,address,&outputDesc->mLatency,outputDesc->mFlags);
//5.,根据output添加outputDesc描述符,保存输出设备描述符对象
addOutput(output, outputDesc);
//6.设置输出设备
setOutputDevice(....);//里面还有一些根据属性选择output,getOutputForAttr等等,根据stratery选择设备由enfine完
成
//7.打开输入设备
mpClientInterface->openInput(....);
//8.更新输出设备
updateDevicesAndOutputs();
}
通过上面的1到8步基本就把整个音频处理系统的架子给搭起来!!!!接下来看看其中的这几个重要的函数
2.2.1 加载配置文件
在AudioPolicyManager(的构造函数中,能找到loadConfig,这个函数负责解析xml配置文件,在这个文件中会找出所有的Interface(audio_hw_module关键字定义的模块)比如primary、usb、a2dp、r_submix(WiDi用)。在每个interface下面会包含若干个Outputs,有的还有Inputs,同时在每个Outputs/Inputs下面又包含若干个Profile,每个Profile描述了该input/output支持sample rate,channel mask, devices &flags。
status_t AudioPolicyManager::loadConfig(const char *path)
status_t AudioPolicyManager::loadOutput(cnode *root, HwModule *module)
void AudioPolicyManager::loadHwModule(cnode *root)
......
AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
: AudioPolicyManager(clientInterface, false /*forTesting*/)
{
loadConfig();//加载配置文件
initialize();//根据配置文件做动作
}
void AudioPolicyManager::loadConfig() {
#ifdef USE_XML_AUDIO_POLICY_CONF
if (deserializeAudioPolicyXmlConfig(getConfig()) != NO_ERROR) {
#else
if ((ConfigParsingUtils::loadConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE, getConfig()) != NO_ERROR)
&& (ConfigParsingUtils::loadConfig(AUDIO_POLICY_CONFIG_FILE, getConfig()) != NO_ERROR)) {
#endif
ALOGE("could not load audio policy configuration file, setting defaults");
getConfig().setDefault();
}
}
系统中的xml被读取之后,以 mConfig(mHwModulesAll, mAvailableOutputDevices, mAvailableInputDevices,mDefaultOutputDevice, static_cast<VolumeCurvesCollection*>(mVolumeCurves.get())的形式保存,后续需要和底层interface交互时,就可以通过这些成员获取相关信息;
......
//加载xml配置文件
static status_t deserializeAudioPolicyXmlConfig(AudioPolicyConfig &config) {
char audioPolicyXmlConfigFile[AUDIO_POLICY_XML_CONFIG_FILE_PATH_MAX_LENGTH];
//其中#define AUDIO_POLICY_XML_CONFIG_FILE_PATH_MAX_LENGTH 128
//#define AUDIO_POLICY_XML_CONFIG_FILE_NAME "audio_policy_configuration.xml"
//#define AUDIO_POLICY_A2DP_OFFLOAD_DISABLED_XML_CONFIG_FILE_NAME \
在AudioPolicyManager创建过程中会通过加载(AudioPolicyManager的构造函数)audio_policy_configuration.xml配置文件来加载音频设备,Android为每种音频接口定义了对应的硬件抽象层。每种音频接口定义了不同的输入输出,一个接口可以具有多个输入或者输出,每个输入输出可以支持不同的设备,通过读取audio_policy_configuration.xml文件可以获取系统支持的音频接口参数,在AudioPolicyManager中会优先加载/vendor/etc/audio_policy_configuration.xml配置文件, 如果该配置文件不存在, 则加载/system/etc/audio_policy_configuration.xml配置文件,统中的audio_policy_configuration.xml被读取之后,以profile的形式保存,后续打开/关闭设备的时候,就通过调用profile获取所有的配置参数;当AudioPolicyManager构造时,它会根据用户提供的audio_policy_configuration.xml来分析系统中有哪些audio接口(primary,a2dp以及usb),然后通过AudioFlinger::loadHwModule加载各audio接口对应的库文件,并依次打开其中的output(openOutput)和input(openInput)打开音频输出时创建一个audio_stream_out通道,并创建AudioStreamOut对象以及新建PlaybackThread播放线程
打开音频输入时创建一个audio_stream_in通道,并创建AudioStreamIn对象以及创建RecordThread录音线程。
2.2.2 初始化各种音频流对应的音量调节点
在AudioPolicyManager.cpp的构造函数中会执行两个方法
AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
: AudioPolicyManager(clientInterface, false /*forTesting*/)
{
loadConfig();
initialize();
}
其中loadConfig方法便会去解析配置文件audio_policy_configuration.xml
void AudioPolicyManager::loadConfig() {
if (deserializeAudioPolicyXmlConfig(getConfig()) != NO_ERROR) {
ALOGE("could not load audio policy configuration file, setting defaults");
getConfig().setDefault();
}
}
调用deserializeAudioPolicyXmlConfig(getConfig()) 方法去解析配置文件时,使用
getConfig()方法传入一个参数,这个参数的类型是AudioPolicyConfig
在AudioPolicyConfig.h中:
class AudioPolicyConfig
{
public:
AudioPolicyConfig(......
: ......
mVolumeCurves(volumes),//音频曲线
......
然后再来看一下deserializeAudioPolicyXmlConfig()的实现
static status_t deserializeAudioPolicyXmlConfig(AudioPolicyConfig &config) {
char audioPolicyXmlConfigFile[AUDIO_POLICY_XML_CONFIG_FILE_PATH_MAX_LENGTH];
std::vector<const char*> fileNames;
status_t ret;
......
fileNames.push_back(AUDIO_POLICY_XML_CONFIG_FILE_NAME);
for (const char* fileName : fileNames) {
for (const auto& path : audio_get_configuration_paths()) {
......
return ret;
}
这段代码做了一个循环,解析了”/odm/etc”, “/vendor/etc”, “/system/etc”这三个路径和
AUDIO_POLICY_XML_CONFIG_FILE_NAME拼接的文件,而
AUDIO_POLICY_XML_CONFIG_FILE_NAME就是audio_policy_configuration.xml
#define AUDIO_POLICY_XML_CONFIG_FILE_NAME "audio_policy_configuration.xml"
通过include的方式包含了两个xml文件
//audio_policy_configuration.xml
<xi:include href="audio_policy_volumes.xml"/>//规定了音频流、输出设备和音量曲线的关系
<xi:include href="default_volume_tables.xml"/>//规定了具体音频曲线的值
因为不同的音频流使用不同的音频曲线,而同一音频流在输出设备不同时也采用不同的音频曲线,
所以必须规定这三者的对应关系,xml中的这种对应关系被serializer.deserialize方法解析后,在代
码中体现为VolumeCurvesCollection-VolumeCurvesForStream-VolumeCurve的对应关系
audio_policy_volumes.xml:这个配置文件描述f(stream,device )= volume-curve的映射关系。
<volume stream="音频类型" deviceCategory="输出设备"
ref="音频曲线"/>
<volume stream="AUDIO_STREAM_RING" deviceCategory="DEVICE_CATEGORY_EXT_MEDIA"
ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
default_volume_tables.xml:这个文件描述不同类型的音量曲线。
......
<reference name="DEFAULT_MEDIA_VOLUME_CURVE">//DEFAULT_MEDIA_VOLUME_CURVE曲线上点的xy值
<!-- Default Media reference Volume Curve -->
<point>1,-5800</point>
<point>20,-4000</point>
<point>60,-1700</point>
<point>100,0</point>
</reference>
......
所以如果想要修改音频曲线,只要修改default_volume_tables.xml文件就行了。想要对(stream,device)使用不同的音频曲线就修改audio_policy_volumes.xml。
AudioPolicymanger调节音量的接口,setStreamVolumeIndex,设置特定流特定设备的音量其中参数device是 Stream->Strategy->Device的方式获得, 这也是AudioPolicy获得设备的标准方式。在分析audiopolicymanager如何实现调节stream的音量时我们先进行一些思考。首先我们知道android的音量有两种描述方式index和DB。这里我们的入参是index。我们首先要完成的一个工作是将index转化为DB。其次,音量调节需要作用到具体的数据流中。而audioflinger是负责具体音频数据流的处理工作!那么我们就需要把音量值(DB)设置给audioflinger。audioflinger当中具体进行数据处理的类是threads。从设计的角度看,audiopolicymanager是不需要知道threads的信息的。但是audiopolicymanager又需要将具体的音量值通知给threads。这怎么办呢?从上面的内容我们可以知道audiopolicymanager在初始化的时候会打开所有的ouput。而audioflinger内部通过map保存了output和thread之间的关系。那么audiopolicymanager在设置音量的时候只需要知道所有支持入参的stream和device的output,并将音量设置给该toutput就行。事实上,setStreamVolumeIndex也真是按照这个思路实现的。
//AudioPolicyManager.cpp
status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream,
int index, audio_devices_t device)
// 1. 判断传入的参数
// 音量不可大于流的最大音量,小于最小音量值
if ((index < mVolumeCurves->getVolumeIndexMin(stream)) ||
(index > mVolumeCurves->getVolumeIndexMax(stream)))
return BAD_VALUE;
...
// 设备需要是输出设备
if (!audio_is_output_device(device))
return BAD_VALUE;
...
// 如果传入的流不能被Mute, 强制使用该流的最高音量
// canBeMuted,现在代码中,没有设置canBeMuted的接口,默认被设置为true
if (!volumeCurves.canBeMuted()) index = volumeCurves.getVolumeIndexMax();
...
// 2. 更新与传入的流,设备的音量值
for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) {
// return (stream1 == stream2)
if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) {
continue;
}
// 更新特定流,特定设备的音量值
VolumeCurves->addCurrentVolumeIndex( device, index);
}
...
// 3. 遍历已经打开的所有的output,对所有的符合条件的output和流设置音量
status_t status = NO_ERROR;
for (size_t i = 0; i < mOutputs.size(); i++) {
// 获得该output的配置信息
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
// curSrcDevice 是根据当前output使用的设备得出的。output和设备的关系是通过route确定的。
// 其中主要对双设备做了处理,一般双设备只选取了speaker
audio_devices_t curSrcDevice = Volume::getDeviceForVolume(desc->device());
//更新
for (int curStream = 0; curStream < AUDIO_STREAM_FOR_POLICY_CNT; curStream++) {
...
// (1) 请求的流必须在当前output中Active(可以理解为正在播放)
// 遍历所有的流,仅对跟请求的流符合的流(当前的代码下可以认为自有请求的流)
if (!streamsMatchForvolume(stream, (audio_stream_type_t)curStream)) {
continue;
}
// 判断流是不是Active
if (!(desc->isStreamActive((audio_stream_type_t)curStream) ||
(isInCall() && (curStream == AUDIO_STREAM_VOICE_CALL)))) {
continue;
}
// (2) 判断请求的设备是否跟当前获得的设备匹配
// 获得请求的流在当前场景下应该使用的设备
routing_strategy curStrategy = getStrategy((audio_stream_type_t)curStream);
audio_devices_t curStreamDevice = Volume::getDeviceForVolume(getDeviceForStrategy(
curStrategy, false /*fromCache*/));
// 请求的设备跟curStreamDevice是否有相同的设备, 是否是默认设备
// 如果两个条件都不符合,不会调整当前流的音量
if ((device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) &&
((curStreamDevice & device) == 0)) {
continue;
}
...
bool applyVolume;
// (3) OutPut的当前设备是否与请求的设备或者请求的设备的子设备相同
if (device != AUDIO_DEVICE_OUT_DEFAULT_FOR_VOLUME) {
curStreamDevice |= device;
applyVolume = (curDevice & curStreamDevice) != 0;
} else {
// (4) 如果请求的设备是默认设备,需要curStreamDevice没有音量配置
applyVolume = !mVolumeCurves->hasVolumeIndexForDevice(
stream, curStreamDevice);
}
if (applyVolume) {
// 调用checkAndSetVolume应用该音量值
status_t volStatus =
checkAndSetVolume((audio_stream_type_t)curStream, index, desc, curDevice,
(stream == AUDIO_STREAM_SYSTEM) ? TOUCH_SOUND_FIXED_DELAY_MS : 0);
我认为上面代码的逻辑是这样的:我们要找到output。但是output可能支持不同的streamtype。这点我们从配置文件可以分析得出。因为output的约束主要是flag,采样率,音频格式,位宽等,而不涉及sreamtype。所以第一步判断output上我们希望修改的streamtype是否是活跃的。其次看该output上输出的设备是否就是我们期望的设备。这里是不是为了避免:outputA上stream是活跃的,ouputB上stream也是活跃的。但是device在outputA上支持,在outputB上不支持。思考一下这种情况可不可能出现。首先stream通过做策略一定要在devcice上播出,而outputB不支持device,stream也就不应该在outputB上活跃。上面的代码是否可以优化一下!
最后调用checkAndSetVolume,( Audiopoicy真正通知Audofinger调节音量的接口是checkAndSetVolume)。
此软件音量曲线的加载就完成了,调节音量时,会根据传入的stream参数先找到getVolumeCurvesForStreamType对象,再根据传入的device参数找到具体的VolumeCurve,最后根据index参数及音量曲线计算出音量的分贝值。(上层设置到AudioPolicy的音量是用户设置的
音量值, 而底层把音量值转换成分贝值才能处理该音量。音量曲线的作用就是做这种转换)在后面就是checkAndSetVolume调用AudioFlinger的setstreamvolume去执行Playbackthread的setstreamvolume操作了。
2.2.3 加载audio policy硬件抽象库
AudioPolicyManager加载完配置文件后,就知道了系统支持的所有音频接口参数,可以为选择音频输出的依据。audio_policy_configuration.xml同时定义了多个audio接口,每一个audio接口包含若干output和input,而每个output和input又同时支持多种输入输出模式,每种输入输出模式又支持若干种设备.最终会去调用到AudioFlinger去加载生成的动态库so
//frameworks/av/services/audiopolicy/service/AudioPolicyClientImpl.cpp
audio_module_handle_t AudioPolicyService::AudioPolicyClient::loadHwModule(const char *name)
{
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
if (af == 0) {
ALOGW("%s: could not get AudioFlinger", __func__);
return AUDIO_MODULE_HANDLE_NONE;
}
return af->loadHwModule(name);//这里直接调用了AudioFlinger::loadHwModule()。
}
我们进到AudioFlinger看看做了啥
audio_module_handle_t AudioFlinger::loadHwModule(const char *name)
{
if (name == NULL) {
return AUDIO_MODULE_HANDLE_NONE;
}
if (!settingsAllowed()) {
return AUDIO_MODULE_HANDLE_NONE;
}
Mutex::Autolock _l(mLock);
return loadHwModule_l(name);
}
......
audio_module_handle_t AudioFlinger::loadHwModule_l(const char *name)
{
//1.是否已经加载过这个interface
for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
if (strncmp(mAudioHwDevs.valueAt(i)->moduleName(), name, strlen(name)) == 0) {
ALOGW("loadHwModule() module %s already loaded", name);
return mAudioHwDevs.keyAt(i);
}
}
//2.加载audio interface
int rc = mDevicesFactoryHal->openDevice(name, &dev);
//3.初始化
rc = dev->initCheck();
//4.添加到全局变量中
audio_module_handle_t handle = (audio_module_handle_t) nextUniqueId(AUDIO_UNIQUE_ID_USE_MODULE);
mAudioHwDevs.add(handle, new AudioHwDevice(handle, name, dev, flags));
}
loadHwModule_l是通过调用openDevice方法来打开加载audio设备的,该方法的实现类是
DevicesFactoryHalHybrid
//frameworks/av/media/libaudiohal/DevicesFactoryHalHybrid.cpp
status_t DevicesFactoryHalHybrid::openDevice(const char *name, sp<DeviceHalInterface> *device) {
if (mHidlFactory != 0 && strcmp(AUDIO_HARDWARE_MODULE_ID_A2DP, name) != 0) {
return mHidlFactory->openDevice(name, device); //Hidl方式加载
}
return mLocalFactory->openDevice(name, device); //旧版本本地加载
}
到DevicesFactoryHalHidl::openDevice看
//DevicesFactoryHalHidl.cpp
status_t DevicesFactoryHalHidl::openDevice(const char *name, sp<DeviceHalInterface> *device) {
if (mDevicesFactory == 0) return NO_INIT;
IDevicesFactory::Device hidlDevice;
status_t status = nameFromHal(name, &hidlDevice);
if (status != OK) return status;
Result retval = Result::NOT_INITIALIZED;
Return<void> ret = mDevicesFactory->openDevice(
DevicesFactory->openDevice:
/DevicesFactory.cpp
Return<void> DevicesFactory::openDevice(IDevicesFactory::Device device, openDevice_cb _hidl_cb) {
int halStatus = loadAudioInterface(moduleName, &halDevice);//加载audio interface
......
_hidl_cb(retval, result);//将加载的设备通过回调匿名方法传递回去
return Void();
}
int DevicesFactory::loadAudioInterface(const char *if_name, audio_hw_device_t **dev)
{
const hw_module_t *mod;
int rc;
//在system/lib/hw/等目录下查找对应的动态库并加载
rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod);
//打开对应的device,并获取hw_device_t指针类型的设备对象
rc = audio_hw_device_open(mod, dev);
......
}
loadHwModlule_l. 加载指定的audiointerface,比如“primary”、“a2dp”或者“usb”。函数load_audio_interface用来加载设备所需的库文件,然后打开设备并创建一个audio_hw_device_t实例。音频接口设备所对应的库文件名称是有一定格式的,比如a2dp的模块名可能是audio.a2dp.so或者audio.a2dp.default.so等等。每种音频设备接口由一个对应的so库提供支持。那么AudioFlinger怎么会知道当前设备中支持上述的哪些接口,每种接口又支持哪些具体的音频设备呢?这是AudioPolicyService的责任之一,即根据用户配置来指导AudioFlinger加载设备接口。当AudioPolicyManager构造时,它会读取厂商关于音频设备的描述文件,然后据此来打开音频接口(如果存在的话)。这一过程最终会调用loadHwModule(AudioFlinger)。完成了audiointerface的模块加载只是万里长征的第一步。因为每一个interface包含的设备通常不止一个,Android系统目前支持的音频设备如下列表所示
大家可能会有疑问:
这么多的输出设备,那么当我们回放音频流(录音也是类似的情况)时,该选择哪一种呢?
而且当前系统中audio interface也很可能不止一个,应该如何选择?
显然这些决策工作将由AudioPolicyService来完成,我们会在下一小节做详细阐述。这里先给大家
分析下,AudioFlinger是如何打开一个Output通道的(一个audiointerface可能包含若干个
output)。
2.2.4设置输出设备
App构造audiotrack时制定了stream type,然后根据stream type来设置属性Attributes,然后
audiomanager根据属性来选择strategy,从再根据strategy类别来获得从哪个设备播放,AudioStream在
Audio Base.h中有定义,包含以下内容:((同时,在AudioSystem.java定义的流类型与audiobase.h中定义的audio_stream_type_t结构体一一对应,所以在JNI中经常可以将其类型强制转换))
// /system/media/audio/include/system/audio-base.h
typedef enum {
AUDIO_STREAM_DEFAULT = -1, // (-1)
AUDIO_STREAM_MIN = 0,
AUDIO_STREAM_VOICE_CALL = 0,
AUDIO_STREAM_SYSTEM = 1,
AUDIO_STREAM_RING = 2,
AUDIO_STREAM_MUSIC = 3,
AUDIO_STREAM_ALARM = 4,
AUDIO_STREAM_NOTIFICATION = 5,
AUDIO_STREAM_BLUETOOTH_SCO = 6,
AUDIO_STREAM_ENFORCED_AUDIBLE = 7,
AUDIO_STREAM_DTMF = 8,
AUDIO_STREAM_TTS = 9,
AUDIO_STREAM_ACCESSIBILITY = 10,
AUDIO_STREAM_ASSISTANT = 11,
#ifndef AUDIO_NO_SYSTEM_DECLARATIONS
/** For dynamic policy output mixes. Only used by the audio policy */
AUDIO_STREAM_REROUTING = 12,
/** For audio flinger tracks volume. Only used by the audioflinger */
AUDIO_STREAM_PATCH = 13,
/** stream for corresponding to AUDIO_USAGE_CALL_ASSISTANT */
AUDIO_STREAM_CALL_ASSISTANT = 14,
#endif // AUDIO_NO_SYSTEM_DECLARATIONS
} audio_stream_type_t;
在现在的大多数fw架构中,AudioStream仅用来标识音频的音量,使用音频属性
AudioAttributes(属性)和AudioStream共同决定AudioStrategy(策略),因为AudioAttributes可以
携带比音频流更多的信息,如:Content、Usage、flag等,
//services/audiopolicy/enginedefault/src/Engine.h
enum legacy_strategy {
STRATEGY_NONE = -1,
STRATEGY_MEDIA,
STRATEGY_PHONE,
STRATEGY_SONIFICATION,
STRATEGY_SONIFICATION_RESPECTFUL,
STRATEGY_DTMF,
STRATEGY_ENFORCED_AUDIBLE,
STRATEGY_TRANSMITTED_THROUGH_SPEAKER,
STRATEGY_ACCESSIBILITY,
STRATEGY_REROUTING,
STRATEGY_CALL_ASSISTANT,
};
根据attributes获取strategy
getStrategyForAttr
然后根据strategy来选择设备
//frameworks/av/services/audiopolicy/enginedefault/src/Engine.cpp
DeviceVector Engine::getDevicesForStrategyInt
最后根据设备来获取output
//frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
audio_io_handle_t AudioPolicyManager::getOutputForDevices(
......
比如说,下面的例子是播放音乐(AUDIO_STREAM_MUSIC)的时候选中的Strategy:
//frameworks/av/services/audiopolicy/enginedefault/src/Engine.cpp
case STRATEGY_REROUTING:
case STRATEGY_MEDIA: {
if (strategy != STRATEGY_SONIFICATION)
......
if (isInCall() && (strategy == STRATEGY_MEDIA)) {//是否在电话中且strage属于媒体类
if ((devices2.isEmpty()) &&
(getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP)) {
devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_HEARING_AID);
}
if ((devices2.isEmpty()) &&
(getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) == AUDIO_POLICY_FORCE_SPEAKER)) {
devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
}
......//都是一些优先级的判断
根据上面的代码,简单做个总结吧:
播放音乐选设备优先级如下
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP(蓝牙高保真设备)
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES(普通蓝牙耳机)
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER(蓝牙小音箱)
//此处属于setForceUse的强制插队,音频焦点,特殊情况如何处理,比如来电后,音乐声音要变小
(if FORCE_SPEAKER)AUDIO_DEVICE_OUT_SPEAKER(扬声器)
AUDIO_DEVICE_OUT_WIRED_HEADPHONE(普通耳机,只能听,不能操控播放)
AUDIO_DEVICE_OUT_LINE
AUDIO_DEVICE_OUT_WIRED_HEADSET(线控耳机)
AUDIO_DEVICE_OUT_USB_HEADSET(USB耳机)
…
AUDIO_DEVICE_OUT_SPEAKER(扬声器)
选好设备就返回device,然后getOutputForDevice
AudioPolicyManager::getOutputForDevice
//处理入参flags
if ((flags & AUDIO_OUTPUT_FLAG_XXX) != 0) {
flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_XXX);
}
//咱一般不是AUDIO_OUTPUT_FLAG_DIRECT,当然是
goto non_direct_output;
......
//播放音乐什么之类的,mediaplayer已经做完decodec.这里一般都是pcm
if (audio_is_linear_pcm(format)) {
//根据指定的stream类型获取匹配的output.实际的路由改变需要等到startOutput被调用的时候
//注意这个函数是getOutputsForDevice,要获取的是一些output,而我们当前讨论的函数是获取一个output.这些outputs从
mOutputs中来.那么mOutputs来自哪里?
SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(device, mOutputs);
// 从匹配到的outputs(请注意,是复数)中选出一个output
output = selectOutput(outputs, flags, format);
}
我们分析ouput的创建和使用过程,不难发现outputs和线程池有很大的相似之处。此外每个ouput都有一个thread。这就是典型的享元设计模式。
那么mOutputs来自哪里?
void AudioPolicyManager::addOutput(audio_io_handle_t output, const sp<SwAudioOutputDescriptor>& outputDesc)
{
outputDesc->setIoHandle(output);
mOutputs.add(output, outputDesc);
updateMono(output); // update mono status when adding to output list
selectOutputForMusicEffects();
nextAudioPortGeneration();
}
从mOutputs中选出和匹配的一些output之后,用selectOutput选中我们真正需要的那一个.
AudioPolicyManager::selectOutput
// select one output among several that provide a path to a particular device or set of
// devices (the list was previously build by getOutputsForDevice()).
// The priority is as follows:
// 1: the output with the highest number of requested policy flags
// 2: the output with the bit depth the closest to the requested one
// 3: the primary output
// 4: the first output in the list
......
//在几个提供一个特定设备或一组路径的路径中选择一个输出
//设备(该列表以前由getOutputsForDevice()构建)。
//优先级如下:
// 1:请求的policy flags数量最多的输出
// 2:bit depth最接近请求的输出
// 3:主输出
// 4:列表中的第一个输出
然后返回选中的output即可.
整个getOutputForAttr就完成了.(attr>>strategy>>device>>output)
setoutputdevices这个函数里还创建patch,也就是建立起output和device之间的关系。
AudioPolicyManager::setOutputDevice
//Duplicated output,output1和output2各来一遍setOutputDevice
if (outputDesc->isDuplicated()) {
muteWaitMs = setOutputDevice(outputDesc->subOutput1(), device, force, delayMs);
muteWaitMs += setOutputDevice(outputDesc->subOutput2(), device, force, delayMs);
return muteWaitMs;
}
...
if (device == AUDIO_DEVICE_NONE) {
resetOutputDevice(outputDesc, delayMs, NULL);
} else {
DeviceVector deviceList;
if ((address == NULL) || (strlen(address) == 0)) {
//mAvailableOutputDevices在APM构造的时候就已经准备好了
//setDeviceConnectionStateInt中也会对新设备做add
deviceList = mAvailableOutputDevices.getDevicesFromType(device);
} else {
deviceList = mAvailableOutputDevices.getDevicesFromTypeAddr(device, String8(address));
}
if (!deviceList.isEmpty()) {
struct audio_patch patch;
outputDesc->toAudioPortConfig(&patch.sources[0]);
patch.num_sources = 1;
patch.num_sinks = 0;
for (size_t i = 0; i < deviceList.size() && i < AUDIO_PATCH_PORTS_MAX; i++) {
deviceList.itemAt(i)->toAudioPortConfig(&patch.sinks[i]);
patch.num_sinks++;
}
//从mAudioPatches中取出patch的index
ssize_t index;
if (patchHandle && *patchHandle != AUDIO_PATCH_HANDLE_NONE) {
index = mAudioPatches.indexOfKey(*patchHandle);
} else {
index = mAudioPatches.indexOfKey(outputDesc->getPatchHandle());
}
//每个output有自己的patchhandle。maudiopatch是整个系统所有的audiopatch。
//处理afPatchHandle
sp< AudioPatch> patchDesc;
audio_patch_handle_t afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
if (index >= 0) {
patchDesc = mAudioPatches.valueAt(index);
afPatchHandle = patchDesc->mAfPatchHandle;
}
关于Audio Patch(就是一个有source和sink的一个结构体)的分析,比较复杂,我们不做赘述了,有兴趣的可以去网上查查资料,它最终会调用AudioFlinger::PlaybackThread::createAudioPatch_l
status_t AudioFlinger::PlaybackThread::createAudioPatch_l(const struct audio_patch *patch,
audio_patch_handle_t *handle)
{
...
if (mOutput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
audio_hw_device_t *hwDevice = mOutput->audioHwDev->hwDevice();
status = hwDevice->create_audio_patch(hwDevice,
patch->num_sources,
patch->sources,
patch->num_sinks,
patch->sinks,
handle);
} else {
char *address;
if (strcmp(patch->sinks[0].ext.device.address, "") != 0) {
//FIXME: we only support address on first sink with HAL version < 3.0
address = audio_device_address_to_parameter(
patch->sinks[0].ext.device.type,
patch->sinks[0].ext.device.address);
} else {
address = (char *)calloc(1, 1);
}
AudioParameter param = AudioParameter(String8(address));
free(address);
param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), (int)type);
status = mOutput->stream->common.set_parameters(&mOutput->stream->common,
param.toString().string());
*handle = AUDIO_PATCH_HANDLE_NONE;
}
if (configChanged) {
mPrevOutDevice = type;
sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
}
...
}
如果supportsAudioPatches.那么就继续createAudioPatch.分别会经过 libaudiohal底下
DeviceHalHidl::createAudioPatch和hardware底下的Device.cpp.然后进入
底下的audio_hw.c中实现的create_audio_patch函数.
如果hal版本过低,不支持audiopatch,AudioPolicy下发的AudioPatch会在AudioFlinger中转
化为set_parameters向Hal下发
out_set_parameter或in_set_parameter完成设备下发
static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
{
struct stream_out *out = (struct stream_out *)stream;
struct audio_device *adev = out->dev;
struct str_parms *parms;
char value[32];
int ret = 0, val = 0, err;
ALOGE("%s: enter: usecase(%d: %s) kvpairs: %s",
__func__, out->usecase, use_case_table[out->usecase], kvpairs);
...
}
关于参数说明:
out->usecase:来自于audiofinger的openOutputStream方法,调用路径请查看:<音频输出设备是
如何决定的>章节,需要注意的是每条音频路径的openOutputStream只会在APS初始化的时候调用一
次,之后音频播放的时候不会再次调用,它会传递到Audio_hw.c的adev_open_output_stream。
adev_open_output_stream
} else if (out->devices == AUDIO_DEVICE_OUT_TELEPHONY_TX) {
...
out->usecase = USECASE_AUDIO_PLAYBACK_AFE_PROXY;
上Hal会根据传入设备的类型来决定usecase的值。
关于第二个参数
kvpairs来自于上文提到的createAudioPatch_l,注意下面这个字段:
param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), (int)type);
在APS初始化的时候,会将系统可用音频路径的PlaybackThread创建好(offload的除外),在这个过程中也会调用可用音频路径的默认输出设备(一般是Speaker,Voice的是听筒)的setOutputDevice,从而为每条可用音频路径设置默认的路由。因此,APS初始化后,会打出如Log:
01-27 05:26:07.504 4588 4588 E APM_AudioPolicyManager: Jon,deviceList size = 1
01-27 05:26:07.506 4588 4595 E AudioFlinger: Jon,address =
01-27 05:26:07.506 4588 4595 E audio_hw_primary: out_set_parameters: Jon, enter: usecase(1: low-latencyplayback) kvpairs: routing=2
01-27 05:26:07.518 4588 4588 E APM_AudioPolicyManager: Jon,deviceList size = 1
01-27 05:26:07.519 4588 4597 E AudioFlinger: Jon,address =
01-27 05:26:07.520 4588 4597 E audio_hw_primary: out_set_parameters: Jon, enter: usecase(12: audio-ullplayback) kvpairs: routing=2
01-27 05:26:07.524 4588 4588 E APM_AudioPolicyManager: Jon,deviceList size = 1
01-27 05:26:07.525 4588 4598 E AudioFlinger: Jon,address =
01-27 05:26:07.525 4588 4598 E audio_hw_primary: out_set_parameters: Jon, enter: usecase(0: deep-bufferplayback) kvpairs: routing=2
01-27 05:26:07.530 4588 4588 E APM_AudioPolicyManager: Jon,deviceList size = 1
01-27 05:26:07.531 4588 4600 E AudioFlinger: Jon,address =
01-27 05:26:07.531 4588 4600 E audio_hw_primary: out_set_parameters: Jon, enter: usecase(38: afe-proxyplayback) kvpairs: routing=65536
但是由于初始化阶段,所有的stream并没有被active,因此select_devices没有机会在这个时候
被调度到
既然如此,那么问题来了,Hal是在什么时候为Stream真正设置输出的呢,答案是在track->start
后真正向Hal下发数据的时候,如下:
//audio_hw.c
static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
size_t bytes)
{
...
if (out->standby) {
out->standby = false;
pthread_mutex_lock(&adev->lock);
if (out->usecase == USECASE_COMPRESS_VOIP_CALL)
ret = voice_extn_compress_voip_start_output_stream(out);
else
ret = start_output_stream(out);
pthread_mutex_unlock(&adev->lock);
/* ToDo: If use case is compress offload should return 0 */
if (ret != 0) {
out->standby = true;
goto exit;
}
if (last_known_cal_step != -1) {
ALOGD("%s: retry previous failed cal level set", __func__);
audio_hw_send_gain_dep_calibration(last_known_cal_step);
}
}
...
}
答案就在start_output_stream中,而且很明显在单次音频的播放中,start_output_stream只会被
调用一次。
int start_output_stream(struct stream_out *out)
{
...
//Hal选择音频的输出设备
select_devices(adev, out->usecase);
...
pcm_open
pcm_prepare
pcm_start
...
}
在后面就是hal与alsa的交互了,我们这里不做赘述
int select_devices(struct audio_device *adev, audio_usecase_t uc_id)
{
...
//获取在start_output_stream中设置的usecase
usecase = get_usecase_from_list(adev, uc_id);
...
//禁止当前声卡设备
if (usecase->out_snd_device != SND_DEVICE_NONE) {
disable_audio_route(adev, usecase);
disable_snd_device(adev, usecase->out_snd_device);
}
//使能新的声卡设备
if (out_snd_device != SND_DEVICE_NONE) {
//检查是否有其他的usecase需要切换路由
check_usecases_codec_backend(adev, usecase, out_snd_device);
enable_snd_device(adev, out_snd_device);
}//这里的enable_snd_device的作用可以理解为通过tinymix进行下面的操作:
//tinymix 'RX3 MIX1 INP1' 'RX1'
//tinymix 'SPK' ‘Switch’
//也就是将BE DAIs ----> device之间的硬件通路打开
...
//使能新的音频路由
enable_audio_route(adev, usecase);
...
}//这里的enable_audio_route的作用可以理解为通过tinymix进行下面的操作:
//tinymix 'PRI_MI2S_RX Audio Mixer MultiMedia1' 1
//也就是将FE PCMs---->BE DAIs之间的硬件通路打开
//
audiopatch流程简介
getNewOutputDevice:检查AudioPatch,如果没有,就用checkStrategyRoute(参数
一:getStrategy(stream),参数二:output)
然后不管两种用哪一个都会AudioPolicyManager::setOutputDevice (从mAudioPatches中取出
patch的index, 处理afPatchHandle)
经过一堆调用流程之后,代码会走到这里
status_t AudioFlinger::PlaybackThread::createAudioPatch_l
通过Device.cpp进入hal的audio_hw.c中实现的static int adev_create_audio_patch函数
//会打fw传下来的log:
LOG_I("in_device:%x in_device_name:%s",sources_device_type,devicetostring(sources_device_type));
LOG_I("out_device:%x out_device_name:%s",sinks_device_type,devicetostring(sinks_device_type));
LOG_I("sinks type:%x sources type:%x",sinks[0].type,sources[0].type);
select_devices会拿set_audio_patch的设备。
2.2.5打开输出设备
取得output之后,需要应用它.
首先
//AudioTrack::createTrack_l()
...
AudioSystem::getLatency(output, &mAfLatency);
...
AudioSystem::getFrameCount(output, &mAfFrameCount);
...
AudioSystem::getFrameCountHAL(output, &afFrameCountHAL);
...
AudioSystem::getSamplingRate(output, &mAfSampleRate);
注意上方调用的参数,第一个入参,第二个是出参(指针)!
以上过程获得了mAfLatency,mAfFrameCount,afFrameCountHAL,mAfSampleRate四个值.注意,全
是
af打头的,表示AudioFlinger端对output的设置.做一些修正调整,变成
mSampleRate,temp(mAfFrameCount和mAfFrameCount,mAfLatency三个参数综合计算).
然后
sp<IAudioTrack> track = audioFlinger->createTrack(streamType,
mSampleRate,
mFormat,
mChannelMask,
&temp,
&flags,
mSharedBuffer,
output,
mClientPid,
tid,
&mSessionId,
mClientUid,
&status,
mPortId);
我们跳到AudioFlinger端去看看
//AudioFlinger::createTrack
...
PlaybackThread *thread = checkPlaybackThread_l(output);
...
首先checkPlaybackThread_l从mPlaybackThreads中检索出output对应的回放线程.
我们之前说过,在AudioPolicyManager构造的时候,会根据audio_policy.conf中的配置,挨个调用
mpClientInterface->openOutput.(最终调用AudioFlinger::openOutput_l)
//frameworks/av/services/audiopolicy/service/AudioPolicyClientImpl.cpp
status_t AudioPolicyService::AudioPolicyClient::openOutput(audio_module_handle_t module,
audio_io_handle_t *output,
audio_config_t *config,
audio_devices_t *devices,
const String8& address,
uint32_t *latencyMs,
audio_output_flags_t flags)
{
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
if (af == 0) {
ALOGW("%s: could not get AudioFlinger", __func__);
return PERMISSION_DENIED;
}
return af->openOutput(module, output, config, devices, address, latencyMs, flags);//这里直接调用了
AudioFlinger::openOutput()。
}
AudioFlinger打开output
//frameworks/av/services/audioflinger/AudioFlinger.cpp
status_t AudioFlinger::openOutput()
{
......
sp<ThreadBase> thread = openOutput_l(module, output, config, *devices, address, flags);
......
}
......
sp<AudioFlinger::ThreadBase> AudioFlinger::openOutput_l(......)//最终调用AudioFlinger::openOutput_
{
// 查找相应的audio interface,查找合适的设备并打开
AudioHwDevice *outHwDev = findSuitableHwDev_l(module, devices);
......
AudioStreamOut *outputStream = NULL;
//在硬件设备上打开一个输出流
status_t status = outHwDev->openOutputStream(
&outputStream,
*output,
devices,
flags,
config,
address.string());
......
//创建PlaybackThread*
sp<PlaybackThread> thread;
if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
//AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD音频流,创建OffloadThread实例
thread = new OffloadThread(this, outputStream, *output, devices, mSystemReady);
ALOGV("openOutput_l() created offload output: ID %d thread %p",
*output, thread.get());
} else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT)
|| !isValidPcmSinkFormat(config->format)
|| !isValidPcmSinkChannelMask(config->channel_mask)) {
//若是AUDIO_OUTPUT_FLAG_DIRECT音频,则创建DirectOutputThread实例
thread = new DirectOutputThread(this, outputStream, *output, devices, mSystemReady);
ALOGV("openOutput_l() created direct output: ID %d thread %p",
*output, thread.get());
} else {
//其他音频流,则创建MixerThread实例
thread = new MixerThread(this, outputStream, *output, devices, mSystemReady);
//关联output和PlaybackThread,添加播放线程
mPlaybackThreads.add(*output, thread);
......
//Primary output情况下的处理:如果当前设备是主设备,则还需要进行相应的设置,包括模式、主音量等等
if ((mPrimaryHardwareDev== NULL) &&flags & AUDIO_OUTPUT_FLAG_PRIMARY)) {undefined
ALOGI("Usingmodule %d has the primary audio interface", module);
mPrimaryHardwareDev = outHwDev;
AutoMutexlock(mHardwareLock);
mHardwareStatus =AUDIO_HW_SET_MODE;
outHwDev->set_mode(outHwDev, mMode);//模式
......
mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME; //测试设备是否支持主音量获取
Android系统是怎么从AudioTrack的start开始之后,一路走到AudioFlinger的Track::start的,我们略
过不提了,毕竟今天的主题是策略.我们知道,AudioFlinger::Track::start中,调用
PlaybackThread::addTrack_l,使沉睡的PlaybackThread被唤醒,然后就调用到了我们重要的
status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track)
{
status = AudioSystem::startOutput(mId, track->streamType(),
track->sessionId());
...
}
status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track)
{
status = AudioSystem::startOutput(mId, track->streamType(),
track->sessionId());
...
}//mId就是PlaybackThread的序号,标识,output!
接下来我们转入startOutput函数
status_t AudioPolicyManager::startOutput(audio_io_handle_t output,
audio_stream_type_t stream,
audio_session_t session)
{
//根据output这个id.找出outputDesc
ssize_t index = mOutputs.indexOfKey(output);
sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(index);
//
if (outputDesc->mPolicyMix != NULL) {
...
} else if (mOutputRoutes.hasRouteChanged(session)) {
//选用新的设备
newDevice = getNewOutputDevice(outputDesc, false /*fromCache*/);
checkStrategyRoute(getStrategy(stream), output);
}
...
status_t status = startSource(outputDesc, stream, newDevice, address, &delayMs);
...
}
2.3 策略制定总结
AudioPolicyService加载解析/vendor/etc/audio_policy.conf或/system/etc/audio_policy.conf
对于配置文件里的每一个module项, new HwModule(name), 放入mHwModules数组
对于module里的每一个output, new IOProfile, 放入module的mOutputProfiles
对于module里的每一个input, new IOProfile, 放入module的mInputProfiles
根据module的name加载厂家提供的so文件 (通过AudioFlinger来加载)
打开对应的output (通过AudioFlinger来open output)