Android 8.1 Audio框架(一)初始化分析

概述

本文将讲述AudioPolicyService、AudioPolicyManager的初始化过程,解析加载xml文件之后生成的模块,研究AudioPolicyManager是如何根据profile打开对应的模块并构建好输出音频数据的路径。

类简介

1.AudioPolicyService:APS是音频框架的服务,在Main_audioserver.cpp中生成,它在第一次强引用的时候会创建AudioCommandThread和AudioPolicyClient,AudioPolicyManager。它主要由AudioSystem通过binder调用,也可以由AudioPolicyClient,AudioPolicyManager直接调用。它的大部分操作都交给AudioPolicyManager来做
2.AudioPolicyClient:APC是AudioPolicyService的内部类。它用于打开关闭输入输出,设置流音量,传递参数给hal层(如audio_hw.c)等;它主要是通过binder跨进程调用AudioFlinger去完成真正的操作。可以由AudioManager通过mpClientInterface去调用它
3.AudioPolicyManager:APM是AudioPolicyService的码农,AudioPolicyService的大部分操作都由他来执行
4.AudioFlinger:AF主要承担音频混合输出,是Audio系统的核心,从AudioTrack来的数据最终都会在这里处理,并被写入到Audio的HAL。
5.DevicesFactoryHalLocal:根据名字加载对应的hal module。比如传进去a2dp相关的名字,会加载到audio.a2dp.default.so
6.DevicesFactoryHalHidl:跨进行加载hidl hal module。我这边的平台是local的,所以hidl相关就不分析了。
7.DevicesFactoryHalInterface:用于创建子类DevicesFactoryHalHybrid。
8.DevicesFactoryHalHybrid:选择创建DevicesFactoryHalLocal或者DevicesFactoryHalHidl,我这里只创建DevicesFactoryHalLocal。
9.DeviceHalLocal:通过私有成员audio_hw_device_t *mDev,直接调用hal代码,用来设置和获取底层参数,打开和关闭stream。
10.StreamOutHalLocal:通过私有成员audio_stream_out_t *mStream直接调用hal代码,用于操作流,比如start、stop、flush、puse操作;还有调用write函数写音频数据到hal层。
11.AudioStreamOutSink:它其实是StreamOutHalLocal的一个wrapper,它也有write函数,不过是通过StreamOutHalLocal来操作的。

时序图

Android 8.1 Audio框架(一)初始化分析_第1张图片初始化过程可以分为四部分:
1.加载audio configuration。
2.加载每一个HwModule。
3.初始化默认输出输入设备。找到默认设备对应的IOProfile,为它创建SwAudioOutputDescriptor,然后openOutput。

加载audio configuration

AudioPolicyManager在初始化的时候会去加载xml文件,解析xml文件,然后把解析出来的信息填充到对应的类中。熟悉audio profile相关信息有助于后面分析代码。下图表示的是相关的类信息。
Android 8.1 Audio框架(一)初始化分析_第2张图片

说明:
HwModuleCollection是一个Vector类,用于保存HwModule,我这里有三个module,一个是primary,一个是a2dp,一个是usb。可以看出我这三个module都是从三个xml文件中解析出来的,每个module都包含有对应xml文件的所有信息。可以使用dumpsys media.audio_policy 把所有的policy信息dump出来,这个dump是调用HwModuleCollection::dump之类的函数,把所有的子集都dump出来。下面就是使用这个命令dump出来的部分信息,右半部分是我手动添加的,dump信息结合代码总结出来的。

W Modules dump:                                 HwModuleCollection::dump  (HwModuleCollection mHwModules)
- HW Module 1:                                              
  - name: primary                                  HwModule::dump  (itemAt(i)->dump)
  - handle: 10
  - version: 2.0
  - outputs:                                                
    output 0:                                               
                                                     IOProfile::dump     (mOutputProfiles[i]->dump)(OutputProfileCollection mOutputProfiles)
    - name: primary output                             AudioPort::dump         [对应xml中<mixPorts>]
    - Profiles:                                          AudioProfileVector::dump     (mProfiles.dump)
        Profile 0:                                          
            - format: AUDIO_FORMAT_PCM_16_BIT              AudioProfile::dump(itemAt(i)->dump)
            - sampling rates:44100
            - channel masks:0x0003
    - flags: 0x0002 (AUDIO_OUTPUT_FLAG_PRIMARY)     IOProfile::dump
    - Supported devices:                            DeviceVector::dump [对应xml中<devicePorts>]  (mSupportedDevices)
      Device 1:                                     DeviceDescriptor::dump (itemAt(i))
      - id:  1
      - tag name: Earpiece
      - type: AUDIO_DEVICE_OUT_EARPIECE                       
      Device 2:
      - id:  2
      - tag name: Speaker
      - type: AUDIO_DEVICE_OUT_SPEAKER                                    
      Device 5:
      - tag name: BT SCO
      - type: AUDIO_DEVICE_OUT_BLUETOOTH_SCO                                          
    output 2:
    - name: voice_tx
    - Profiles:
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:8000, 16000
            - channel masks:0x0001
    - flags: 0x0000 (AUDIO_OUTPUT_FLAG_NONE)
    ...........   
  - inputs:                                                 HwModule::dump  (itemAt(i)->dump)
    input 0:                                                       

                                                               IOProfile::dump (mInputProfiles[i]->dump)                                                       
    - name: primary input                                       AudioPort::dump     [这个对应xml文件里的<mixPorts>]                                                                 
    - Profiles:                                                 AudioProfileVector::dump     (mProfiles.dump)
        Profile 0:
            - format: AUDIO_FORMAT_PCM_16_BIT
            - sampling rates:8000,16000,..., 44100, 48000
            - channel masks:0x000c, 0x0010, 0x0030
    - flags: 0x0000 (AUDIO_INPUT_FLAG_NONE)                   IOProfile::dump 
    - Supported devices:                                      DeviceVector::dump [对应xml中<devicePorts>](mSupportedDevices)
      Device 1:                                               DeviceDescriptor::dump (itemAt(i))
      - id:  4
      - tag name: Built-In Mic
      - type: AUDIO_DEVICE_IN_BUILTIN_MIC   
 * 从xml中的routes解析出来的new AudioPolicyManager--> PolicySerializer::deserialize--> HwModule::setRoutes
 * --> HwModule::refreshSupportedDevices 这个函数会去检查routes,检查通过后把source device和sink device放入
 * IOProfile::mSupportedDevices中,加入到这个结构体之后,估计就不需要原始的route信息了,直接从IOProfile就可以知道
 * source和sink的对应关系。随后IOProfile存储的mSupportedDevices会被用于创建SwAudioOutputDescriptor
   Audio Routes (9):
  - Route 1:			
    - Type: Mix
    - Sink: Earpiece
    - Sources: 
        primary output 
        compressed_offload 
        BT SCO Headset Mic 
   ...........  
Inputs dump:	dump出当前在使用的输入源
- Input 38 dump:
 ID: 11
 Sampling rate: 16000
 Format: 1
 Channels: 0000000c
 Devices 80000004		mic录音的,由于车机有一直在录音,所以这个一直存在
 Audio Sessions:
   Audio session 1:
   - session: 25
   - owner uid: 10018
   - input source: 1
   - format: 00000001
   - sample: 16000
   - channel mask: 0000000c
   - is soundtrigger: false
   - open count: 1
   - active count: 1
* 收音机相关input,软件回路的收音机会用AudioRecord去录取收音机的声音再使用audiotrack播放。
* 当收音机启动的时候才会有,会调用AudioRecord::openRecord_l--->AudioSystem::getInputForAttr--
* -->AudioPolicyManager::getInputForAttr-->AudioPolicyManager::getInputForDevice--
* -->addInput(input, inputDesc) 添加到mInputs中,这样dump就可以dump出来了
* 当切到音乐播放器播放的时候,会调用AudioPolicyManager的stopInput和
* releaseInput,然后releaseInput会调用closeInput把这个input给释放掉,被释放之后就dump不到了。
* 
- Input 46 dump:
 ID: 13
 Sampling rate: 32000
 Format: 1
 Channels: 0000000c
 Devices 80002000	
 Audio Sessions:
   Audio session 1:
   - session: 33
   - owner uid: 1041
   - input source: 1998
   - format: 00000001
   - sample: 32000
   - channel mask: 0000000c
   - is soundtrigger: false
   - open count: 1
   - active count: 1      

可以看出这个信息是属于primary这个module的,也就是对应audio.primary.default.so这个库。module可能会有多个output,多个input,
每一个output或者input对应一个IOProfile。我们来看下上面的output 0,它只有一个profile,支持16位pcm,44100采样率,channel masks为0x0003,这个值对应AUDIO_CHANNEL_OUT_STEREO,也就是立体声的意思。这些采样率等信息存放在AudioPort里面的AudioProfile中。output 0支持好几个devices,比如AUDIO_DEVICE_OUT_SPEAKER、AUDIO_DEVICE_OUT_BLUETOOTH_SCO等等。这些device经常拿来作为选择哪一个module的指标。这些device信息都存放在DeviceDescriptor中。

加载HwModule

AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface)....{
	//加载xml文件,填充对应的类,填充到mHwModules中
    mVolumeCurves = new VolumeCurvesCollection();
    AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices...)
    if (deserializeAudioPolicyXmlConfig(config) != NO_ERROR) {
    	....
    }
    for (size_t i = 0; i < mHwModules.size(); i++) {
        mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->getName());	//加载每一个HwModule
        ...
    }
}

mpClientInterface指向的是AudioPolicyClient,AudioPolicyClient::loadHwModule又通过IAudioFlinger调用到AudioFlinger。AudioFlinger的loadHwModule又调用了loadHwModule_l,所以mpClientInterface->loadHwModule最终调用到的是AudioFlinger::loadHwModule_l。

audio_module_handle_t AudioFlinger::loadHwModule_l(const char *name)
{
    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);		//如果存在,则直接返回
        }
    }
    //到了这里说明没有打开过模块,需要打开。
    sp<DeviceHalInterface> dev;
    int rc = mDevicesFactoryHal->openDevice(name, &dev);	
    .....
}

这里调用到DeviceHalInterface的openDevice函数,这里函数涉及的内容有点多,我这里先给出结论:它会根据传递进来的名字,打开对应的hal库,比如打开audio.a2dp.default.so,然后把句柄等信息保存在AudioHwDevice对象中,并把这个对象添加到mAudioHwDevs中。这样一个mAudioHwDevs元素就是一个so库。好了,结论已经给出来了,现在来分析过程。不过这个过程涉及到很多类,我这边把类图列举出来,这样结构比较清晰。
Android 8.1 Audio框架(一)初始化分析_第3张图片
说明:箭头关系参考UML类图(Class Diagram)中类与类之间的关系及表示方式 不过AudioFlinger和PlaybackThread之间的箭头是错误的。PlaybackThread是AudioFlinger的内部类,而且生命周期不一样,不能用那个箭头表示,应该使用在这里插入图片描述这种箭头表示。
先从AudioFlinger初始化的时候开始看。

AudioFlinger::AudioFlinger(){
	mDevicesFactoryHal = DevicesFactoryHalInterface::create();	
}
sp<DevicesFactoryHalInterface> DevicesFactoryHalInterface::create() {
    return new DevicesFactoryHalHybrid();
}
DevicesFactoryHalHybrid::DevicesFactoryHalHybrid()
        : mLocalFactory(new DevicesFactoryHalLocal()),
          mHidlFactory(
#ifdef USE_LEGACY_LOCAL_AUDIO_HAL
                  nullptr
#else
                  new DevicesFactoryHalHidl()
#endif
                       ) {
}

可以看出DevicesFactoryHalHybrid在初始化的时候会根据需求选择初始化本地类DevicesFactoryHalLocal还是hidl类DevicesFactoryHalHidl。我这边都是本地类,所以不分析DevicesFactoryHalHidl了。所以 AudioFlinger::loadHwModule_l中的mDevicesFactoryHal->openDevice调用的是DevicesFactoryHalHybrid::openDevice。来看看openDevice函数会做什么操作。

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);	//调用DevicesFactoryHalLocal::openDevice
    }
    return mLocalFactory->openDevice(name, device);
}
status_t DevicesFactoryHalLocal::openDevice(const char *name, sp<DeviceHalInterface> *device) {
    audio_hw_device_t *dev;
    status_t rc = load_audio_interface(name, &dev);	//加载hardware module
    if (rc == OK) {
        *device = new DeviceHalLocal(dev);
    }
    return rc;
}
static status_t load_audio_interface(const char *if_name, audio_hw_device_t **dev)//根据名字加载对应的hardware module
{
    const hw_module_t *mod;
    rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod);audio_hw_device_open(mod, dev);
     rc = audio_hw_device_open(mod, dev);
    return rc;
}
DeviceHalLocal::DeviceHalLocal(audio_hw_device_t *dev)
        : mDev(dev) {
}

原来DevicesFactoryHalHybrid::openDevice就是调用 DevicesFactoryHalLocal::openDevice去加载对应的hardware module。比如我这里传入的是a2dp相关的名字,所以我这里加载的so是audio.a2dp.default.so。然后把audio_hw_device_t作为参数传递给DeviceHalLocal,DeviceHalLocal把这个参数保存在自己的私有变量中audio_hw_device_t *mDev。
所以,loadHwModule_l传递回去的dev就是等于DeviceHalLocal,该类保存有hardware module相关信息。然后dev又作为参数传递给AudioHwDevice,这样AudioHwDevice就拥有访问hardware module的能力了。

audio_module_handle_t AudioFlinger::loadHwModule_l(const char *name){
	...
    sp<DeviceHalInterface> dev;	
    int rc = mDevicesFactoryHal->openDevice(name, &dev); //dev 等于DeviceHalLocal
    ...
    mAudioHwDevs.add(handle, new AudioHwDevice(handle, name, dev, flags));
}

到了这里,刚才那个类图的上面部分的箭头关系已经理清楚了。mpClientInterface->loadHwModule部分已经讲解完了,现在继续往下看。

打开输出设备

AudioPolicyManager::AudioPolicyManager(...)...{
	for (size_t i = 0; i < mHwModules.size(); i++) {
		mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->getName());	
		for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++){	//每一个module下面都有一个或这多个IOProfile
			const sp<IOProfile> outProfile = mHwModules[i]->mOutputProfiles[j];	//取出每一个IOProfile
			audio_devices_t profileType = outProfile->getSupportedDevicesType();
			if ((profileType & mDefaultOutputDevice->type()) != AUDIO_DEVICE_NONE) {
                profileType = mDefaultOutputDevice->type(); //如果xml文件中有设置默认设备,则遍历直到找到默认设备对应的IOProfile
            }
            //为默认设备的IOProfile创建SwAudioOutputDescriptor,它保存着支持的输出格式,采样率,声道类型等信息
            sp<SwAudioOutputDescriptor> outputDesc = new SwAudioOutputDescriptor(outProfile, mpClientInterface);
            //从outputDesc中取出信息,保存到config中
            audio_config_t config = AUDIO_CONFIG_INITIALIZER;
            config.sample_rate = outputDesc->mSamplingRate;	
            config.channel_mask = outputDesc->mChannelMask;
            config.format = outputDesc->mFormat;
            //打开输出设备
            status_t status = mpClientInterface->openOutput(outProfile->getModuleHandle(),&output,&config...);
		}
	}
}

mpClientInterface->openOutput跟loadHwModule类似,最终会调用到AudioFlinger::openOutput。

status_t AudioFlinger::openOutput(...){
    sp<ThreadBase> thread = openOutput_l(module, output, config, *devices, address, flags);
}
sp<AudioFlinger::ThreadBase> AudioFlinger::openOutput_l(...){
	AudioHwDevice *outHwDev = findSuitableHwDev_l(module, devices);	//加载对应的AudioHwDevice
	AudioStreamOut *outputStream = NULL;
    status_t status = outHwDev->openOutputStream(&outputStream, *output, devices,flags,config,address.string());
}

到了这里,我们可以来看看上面那个类图的下半部分了。来看看AudioHwDevice::openOutputStream会做什么

status_t AudioHwDevice::openOutputStream(AudioStreamOut **ppStreamOut,audio_io_handle_t handle,audio_devices_t devices...)
{
	AudioStreamOut *outputStream = new AudioStreamOut(this, flags);
	status_t status = outputStream->open(handle, devices, config, address);
}
AudioStreamOut::AudioStreamOut(AudioHwDevice *dev, audio_output_flags_t flags)
        : audioHwDev(dev)...	//保存有AudioHwDevice对象
{
}
AudioStreamOut::open(...){
	sp<StreamOutHalInterface> outStream;
	//hwDev()等于mHwDevice,所以hwDev()->openOutputStream相当于调用DeviceHalLocal::openOutputStream
	 int status = hwDev()->openOutputStream( handle,devices,customFlags,config,address,&outStream);
    if (status == NO_ERROR) {
        stream = outStream;
        ...
    }
	...
}
sp<DeviceHalInterface> AudioStreamOut::hwDev() const
{
    return audioHwDev->hwDevice();
}
class AudioHwDevice {
	sp<DeviceHalInterface> hwDevice() const { return mHwDevice; }
}
status_t DeviceHalLocal::openOutputStream(...sp<StreamOutHalInterface> *outStream) {
    audio_stream_out_t *halStream;
    int openResut = mDev->open_output_stream(   //调用hardware的open_output_stream函数
            mDev, handle, devices, flags, config, &halStream, address);
    if (openResut == OK) {
        *outStream = new StreamOutHalLocal(halStream, this);//把输出流保存起来,以后写音频数据就往这个接口写就行。
    }
    return openResut;
}

可以看出StreamOutHalLocal中保存有输出流的接口,以后写音频数据就调用里面的write函数去写就行了。然后StreamOutHalLocal对象会被保存到AudioStreamOut的私有成员 sp stream中。现在我们有了AudioStreamOut这个对象,我们来看看openOutput_l中还会做什么操作。

sp<AudioFlinger::ThreadBase> AudioFlinger::openOutput_l(...){
    AudioStreamOut *outputStream = NULL;
    status_t status = outHwDev->openOutputStream( &outputStream,...)
    if (status == NO_ERROR) {
        if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
        } else {
            sp<PlaybackThread> thread;
            if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
            } else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT)....)
            } else {	//我的primary设备只走这个分支
                thread = new MixerThread(this, outputStream, *output, devices, mSystemReady);
            }
            mPlaybackThreads.add(*output, thread);
            return thread;
        }
    }

}

可以看出,之前创建的AudioStreamOut作为MixerThread的参数传递进去了。这个很容易理解,MixerThread是一个混音线程,混音之后肯定要输出音频数据的,这里的AudioStreamOut作为向音频设备的输出类,肯定是要作为参数传递进去的。

你可能感兴趣的:(Android,8.1,Audio)