Android13音频子系统分析(二)---初始化

目录

一、AudioPolicyService初始化

1.1 AudioPolicyService::onFirstRef()函数

1.2 AudioCommandThread线程

1.3 AudioPolicyManager初始化

1.3.1 解析audio_policy_configuration.xml配置文件

1.3.2 解析audio_policy_engine_configuration.xml配置文件

1.3.3 AudioPolicyManager::onNewAudioModulesAvailableInt()函数

1.3.4 AudioPolicyManager::updateDevicesAndOutputs()函数

二、AudioFlinger初始化

2.1 AudioFlinger::loadHwModule()函数

2.2 AudioFlinger::openOutput()函数

三、AudioService初始化


        本文我会分别介绍AudioFlinger、AudioPolicyService和AudioService这三个模块的初始化过程。AudioHAL进程的核心源码AOSP里面没有,所以这里不做介绍。想了解AudioHAL进程的启动流程,可以从/hardware/interfaces/audio/common/all-versions/default/service/service.cpp文件的main()函数入手,进行分析。

        大家知道分析代码的执行流程,一般画时序图比较合适,但是我在分析的过程中发现,当跟进一个复杂模块的函数调用流程时,画出来的时序图会非常大,完全看不清楚,所以,这里我会使用伪代码的方式来说明调用流程。

        AudioPolicyService和AudioFlinger都是运行在AudioServer进程中的模块,它们的入口是在/frameworks/av/media/audioserver/main_audioserver.cpp文件中的main()函数中,由init进程通过解析audioserver.rc文件启动。main()函数干的事也比较简单,就是创建AudioPolicyService和AudioFlinger对象,并将它们两个作为Binder服务,添加进ServiceManager中。

        由于AudioPolicyService和AudioFlinger都继承了RefBase类,所以它们的初始化函数有两个:构造函数和onFirstRef()函数。不了解Android RefBase类和强弱指针机制的朋友,可以在网上搜一下,写这部分的文章很多。

一、AudioPolicyService初始化

        AudioPolicyService的构造函数撒也没干,所以它的初始化入口就只剩下了一个onFirstRef()函数。下面我们看看onFirstRef()函数干了什么事。

1.1 AudioPolicyService::onFirstRef()函数

        总体来说onFirstRef()函数主要干了三件事:

  1. 创建两个AudioCommandThread,名称为"ApmAudio"和"ApmOutput"。这两个是循环运行的独立线程。ApmAudio线程主要用来通知AudioFlinger设置路由、进行音量配置。ApmOutput线程主要用来通知上层注册的监听者有数据状态更新。
  2. 调用createAudioPolicyManager()函数,创建并初始化AudioPolicyManager模块。
  3. 调用AudioSystem.cpp的audioPolicyReady()函数,通知AudioFlinger自己已经初始化完成了。

        调用流程如下:

AudioPolicyService.cpp->onFirstRef()
    |-->new AudioCommandThread("ApmAudio")
    |-->new AudioCommandThread("ApmOutput")
    |-->AudioPolicyService.cpp->loadAudioPolicyManager()//加载"libaudiopolicymanagercustom.so",默认没有这个库
    |-->AudioPolicyService.cpp->createAudioPolicyManager()//创建并初始化AudioPolicyManager对象
    |-->AudioPolicyManager.cpp->canBeSpatializedInt()//判断当前系统中是否支持空间音频。只有存在AUDIO_OUTPUT_FLAG_SPATIALIZER的流才代表支持。如果存在,就创建Spatializer对象。同时,空间音频功能目前只支持AUDIO_USAGE_MEDIA和AUDIO_USAGE_GAME这两个场景。
    |-->AudioSystem.cpp->audioPolicyReady()
        |-->AudioFlinger.h->audioPolicyReady()//通知AudioFlinger,自己已经初始化完成

1.2 AudioCommandThread线程

        AudioCommandThread是AudioPolicyService定义的内部类,继承了Android标准的循环线程类Thread.h。所以,当它的run()函数被调用后,线程就会循环一直调用threadLoop()函数。我们来看一下AudioCommandThread类的初始化函数AudioCommandThread::onFirstRef()函数。在这个函数中它调用了父类Thread.h的run()函数,所以当AudioCommandThread对象被创建时,就会启动此线程。

        在线程运行函数AudioCommandThread::threadLoop()中,它会一直遍历自己的消息队列Vector < sp<AudioCommand> > mAudioCommands,当消息队列中没有待处理的消息时,它就会调用Condition类的wait()函数,让自己这个线程睡眠。而外部在向线程的消息队列中插入数据时,又会调用Condition类的signal()函数,将当前线程唤醒。AudioFlinger中的PlaybackThread线程,也是采用这种方法实现:当有播放track时,唤醒线程。没有播放时,线程睡眠,降低CPU占用率,减少功耗。

/**
*向AudioCommandThread的消息队列中添加新消息
**/
status_t AudioPolicyService::AudioCommandThread::sendCommand(sp<AudioCommand>& command, int delayMs){
     insertCommand_l(command, delayMs);//插入新的待处理消息
     mWaitWorkCV.signal();//唤醒当前线程
}

/**
*AudioCommandThread线程循环运行函数
*/
bool AudioPolicyService::AudioCommandThread::threadLoop(){
    if (waitTime == -1) {
    mWaitWorkCV.wait(mLock);//让当前线程睡眠
    } else {
    mWaitWorkCV.waitRelative(mLock, waitTime);//让当前线程睡眠指定的时间
    }
}

1.3 AudioPolicyManager初始化

        在AudioPolicyService.cpp::createAudioPolicyManager()函数中,会干两件事:new AudioPolicyManager对象,然后调用它的initialize()函数。

1.3.1 解析audio_policy_configuration.xml配置文件

        我们先来看AudioPolicyManager的构造函数,它会调用loadConfig()函数,该函数会通过Serializer.cpp工具来解析audio_policy_configuration.xml配置文件,然后将解析到的配置信息保存到AudioPolicyManager类的AudioPolicyConfig对象中。代码调用流程如下:

AudioPolicyService.cpp->createAudioPolicyManager()
    |-->AudioPolicyManager.cpp->AudioPolicyManager()
        |-->AudioPolicyManager.cpp->loadConfig()
            |-->AudioPolicyManager.cpp->deserializeAudioPolicyXmlConfig()
                |-->Serializer.cpp->deserializeAudioPolicyFile()

        audio_policy_configuration.xml配置文件中定义的各种节点,与AudioPolicyManager中的数据结构类型之间的映射关系如下:

  • <module>节点对应的是HwModule类。
  • <mixPort>节点对应的是IOProfile类,输出流对应的是OutputProfile子类。输入流对应的是InputProfile子类。
  • <devicePort>节点对应的是DeviceDescriptor类。
  • <profile>节点对应的是AudioProfile类,这个类定义在libaudiofoundation目录中。用于描述mixPort和devicePort的配置信息。比如支持什么样的采样率、channel个数、format格式。
  • <route>节点对应的是AudioRoute类。描述的是OutputProfile和DeviceDescriptor的连接关系。
  • <defaultOutputDevice>节点用于表述默认的输出物理设备,手机一般配置的是扬声器。它保存在AudioPolicyConfig对象的mDefaultOutputDevice成员变量中。
  • <attachedDevices>节点代表的是系统一开机就可以使用的输入输出硬件,比如扬声器、内置Mic。保存在AudioPolicyConfig对象的mOutputDevices成员变量和mInputDevices成员变量中。而这两个变量指针引用的是AudioPolicyManager对象的mOutputDevicesAll和mInputDevicesAll变量,所以也保存在这两个变量中。

        从上面的数据结构映射关系,结合上一篇Android13音频子系统分析(一)---整体架构中对AudioPolicyService模块的分析,可以看出, audio_policy_configuration.xml文件的作用就是配置当前平台支持哪些硬件设备,默认已加载了哪些硬件设备,并定义平台支持哪些OutStream和InputStream,以及这些IOStream能够与哪些硬件设备进行连接。

1.3.2 解析audio_policy_engine_configuration.xml配置文件

        AudioPolicyManager::initialize()函数是AudioPolicyManager初始化的核心,它会创建并初始化Engine对象,Engine的父类EngineBase在其构造函数中会解析audio_policy_engine_configuration.xml配置文件,然后根据从配置文件中获取到的信息,通知AudioFlinger加载HwModule、创建PlaybackThread。以下是代码调用流程:

AudioPolicyManager.cpp->initialize()
    |-->Engine.cpp->Engine()
        |-->EngineBase.cpp->loadAudioPolicyEngineConfig()//解析audio_policy_engine_configuration.xml配置文件,将解析的音量配置保存到mVolumeGroups对象中,解析的上层场景配置保存到mProductStrategies对象中。

    |-->Engine.cpp->updateDeviceSelectionCache()//更新每个strategy对应的devices,保存到mDevicesForStrategies Map集合中。由于此时AudioPolicyManager的mAvailableOutputDevices集合在onNewAudioModulesAvailableInt()函数中才会初始化,所以此时调用此函数是无法初始化每个strategy对应的devices。

    |-->AudioPolicyManager.cpp->onNewAudioModulesAvailableInt()//通知AudioFlinger打开HwModule,并创建PlaybackThread。然后向mHwModules列表中添加通过AudioFlinger成功打开的HwModule对象。

    |-->AudioPolicyManager.cpp->updateDevicesAndOutputs()//更新每个strategy对应的devices
        |-->Engine.cpp->updateDeviceSelectionCache()

        在EngineBase.cpp->loadAudioPolicyEngineConfig()函数中,会解析audio_policy_engine_configuration.xml配置文件。包含三个配置文件:audio_policy_engine_product_strategies.xml、audio_policy_engine_stream_volumes.xml、audio_policy_engine_default_stream_volumes.xml。这些文件的作用是配置不同播放场景下应该选择的设备路由策略,每种场景对应的音量等级,以及该场景下对应的输出设备的音量曲线。

        当解析完这些配置文件后,会把其中的数据保存到EngineBase类的两个成员变量中:mProductStrategies集合和mVolumeGroups集合。

下面我介绍一下这些配置文件中涉及到的AudioAttributes、StreamType、ProductStrategy、VolumeGroup、deviceCategory、VolumeCurve这些数据结构的作用,以及它们之间的关联关系。

  • AudioAttributes:描述的是一个音频使用场景。比如音乐播放场景可以用CONTENT_TYPE_MUSIC加上USAGE_MEDIA来表示;通话场景可以用CONTENT_TYPE_SPEECH加上USAGE_VOICE_COMMUNICATION来表示。它对应在Java世界中的定义是在frameworks/base/media/java/android/media/AudioAttributes.java文件中。在C/C++世界中的定义是在system/media/audio/include/system/audio.h头文件中的audio_attributes_t结构体。在audio_policy_engine_product_strategies.xml配置文件中对应的是<Attributes>节点。
  • StreamType:Android早期用于表示音频使用场景的变量。目前在应用API层已经改成用AudioAttributes来替代,一种StreamType可以包含多个不同的AudioAttributes。在AudioPolicyManager实现的音频策略中,还是会基于StreamType来定义不同的音量类型。StreamType这里的stream和音频框架层/HAL层定义的StreamOut/StreamIn中的stream并不是一一对应的关系。StreamType描述的是场景,比如AUDIO_STREAM_VOICE_CALL和AUDIO_STREAM_MUSIC。而StreamIO描述的是系统中的音频输入输出流,比如AUDIO_OUTPUT_FLAG_PRIMARY、AUDIO_OUTPUT_FLAG_DIRECT。StreamType在Java世界中的定义是在AudioManager.java文件中。在C/C++世界中的定义是在system/media/audio/include/system/audio-hal-enums.h头文件中的audio_stream_type_t枚举。在audio_policy_engine_product_strategies.xml配置文件中对应的是<AttributesGroup>节点的"streamType"标签。
  • ProductStrategy:代表的是硬件设备选择策略。比如在当前策略下,应该选择使用扬声器播放还是耳机播放。一个ProductStrategy可以包含多种不同的StreamType。它在Java世界中的定义是frameworks/base/media/java/android/media/audiopolicy/AudioProductStrategy.java,这个类是一个hide class,所以普通的3rd APP是无法使用的。在C++中的定义是在frameworks/av/services/audiopolicy/engine/common/include/ProductStrategy.h文件中。在audio_policy_engine_product_strategies.xml配置文件中对应的是<ProductStrategy>节点。
  • VolumeGroup:代表的是一种StreamType对应的音量类型。VolumeGroup中定义了这种音量类型的最小音量等级、最大音量等级、以及在不同硬件设备下应该采用的音量曲线。它在Java中的定义是在frameworks/base/media/java/android/media/audiopolicy/AudioVolumeGroup.java,也是一个hide class。在C++中的定义是在frameworks/av/services/audiopolicy/engine/common/include/VolumeGroup.h。在audio_policy_engine_product_strategies.xml配置文件中对应的是<AttributesGroup>节点的"volumeGroup"标签,详细的定义是在audio_policy_engine_stream_volumes.xml文件中的<volumeGroup>节点中。
  • deviceCategory:代表的一类硬件设备类型。每类不同的设备类型在不同的StreamType场景下,会使用不同的音量曲线。一个deviceCategory会对应多种真实的硬件设备,比如DEVICE_CATEGORY_HEADSET(耳机类型)就会包含AUDIO_DEVICE_OUT_WIRED_HEADSET(有线耳机)和AUDIO_DEVICE_OUT_BLUETOOTH_A2DP(蓝牙耳机)。deviceCategory只在C++框架层定义和使用,它的定义是在/frameworks/av/services/audiopolicy/common/include/Volume.h文件中的device_category枚举。在audio_policy_engine_stream_volumes.xml配置文件中对应的是<volume>节点的"deviceCategory"标签。
  • VolumeCurve:代表的一个音量曲线,供每类不同的硬件设备类型使用。如<point>33,-2800</point>,表示的是音量在33%时,使用-28dB的增益。VolumeCurve也只在C++框架层定义和使用,它的定义是在frameworks\av\services\audiopolicy\engine\common\include\VolumeCurve.h文件中。在audio_policy_engine_stream_volumes.xml配置文件中用<volume>节点来包含多个<point>定义。也可以在audio_policy_engine_default_stream_volumes.xml文件中定义<reference>节点,然后让<volume>节点来引用。这样,不同的硬件设备使用相同的音量曲线时,就可以直接引用,不用重复定义了。

        下图表示的是AudioAttributes、StreamType、ProductStrategy、VolumeGroup、deviceCategory、VolumeCurve之间的关联关系:

从图中可以看出:

  • 一个ProductStrategy包含多种StreamType。
  • 一个StreamType包含多种AudioAttributes。
  • 一个StreamType对应一个VolumeGroup。
  • 一个VolumeGroup包含多种deviceCategory。
  • 一个deviceCategory对应一个VolumeCurve。

即:同一个硬件播放设备,在不同的StreamType场景下,会使用不同的音量曲线。

1.3.3 AudioPolicyManager::onNewAudioModulesAvailableInt()函数

        当解析完配置文件后,AudioPolicyManager.cpp的initialize()函数就会调用onNewAudioModulesAvailableInt()函数。此函数会根据解析到的配置信息,通知AudioFlinger加载AudioModule,打开PlaybackThread。下面以播放场景(OutputProfile)举例列出其代码调用流程,录制场景(InputProfile)的逻辑类似。

AudioPolicyManager.cpp->onNewAudioModulesAvailableInt()
    |-->AudioPolicyClientImpl.cpp->AudioPolicyService::AudioPolicyClient::loadHwModule()
        |-->AudioFlinger.cpp->loadHwModule()//通知AudioFlinger加载AudioModule

    |-->AudioOutputDescriptor.cpp->SwAudioOutputDescriptor::open()
        |-->AudioPolicyClientImpl.cpp->AudioPolicyService::AudioPolicyClient::openOutput()
            |-->AudioFlinger.cpp->openOutput()//通知AudioFlinger,创建PlaybackThread,并打开StreamOut。

    |-->AudioPolicyManager.cpp->setEngineDeviceConnectionState()//遍历当前IOProfile对应的所有可用的devices,然后逐个进行设置
        |-->EngineBase.cpp->setDeviceConnectionState()
            |-->LastRemovableMediaDevices.cpp->setRemovableMediaDevices()//向mMediaDevices列表的头部添加此device,这个列表中保存的是可使用的有线外设和无线蓝牙外设,内置的设备如speaker不会被保存。

    |-->AudioPolicyManager.cpp->addOutput()//在成员变量mOutputs集合中保存SwAudioOutputDescriptor对象
        |-->AudioPolicyManager.cpp->applyStreamVolumes()//设置当前outputStream在不同StreamType场景下应该使用的音量大小

    |-->AudioPolicyManager.cpp->setOutputDevices()//设置当前OutputStream支持的播放设备类型。将其保存到SwAudioOutputDescriptor的mDevices集合中。
        |-->AudioPolicyManager.cpp->installPatch()//通过AudioFlinger创建一个AudioPatch,source是当前的OutputStream,sink目前支持的播放设备。
            |-->AudioPolicyClientImpl.cpp->AudioPolicyService::AudioPolicyClient::createAudioPatch()
                |-->PatchPanel.cpp->AudioFlinger::createAudioPatch()

针对onNewAudioModulesAvailableInt()函数的实现逻辑,我觉得有以下几点需要说明一下:

  • AudioPolicyManager::mHwModulesAll集合中保存的是从配置文件中解析出来的所有HwModule对象,而AudioPolicyManager::mHwModules集合中只保存通过AudioFlinger打开成功的HwModule对象。
  • 初始化后,到底通知AudioFlinger创建了多少PlaybackThread?是不是在配置文件中申明的<mixPort>,都会被创建PlaybackThread?答案是否定的。只有当前的OutputSream关联的devices中,存在可用的device时,才会创建。那么什么是可用的device?只要在audio_policy_configuration.xml中申明的<attachedDevices>,就代表的是可用device。而像有线耳机、无线蓝牙设备这些,刚开机时并不是可用的Device。要等到AudioService监听到它们连接上时,才会通知AudioPolicyManager可用。所有可用的播放设备都会保存在AudioPolicyManager::mAvailableOutputDevices集合中。
  • EngineBase::mLastRemovableMediaDevices集合中只保存的是播放类型的并且可插拔的设备。比如有线耳机或无线蓝牙耳机。不会保存内置的设备,比如扬声器和听筒。当有外设连接上可用时,上层AudioService会通知AudioPolicyManager将它们保存到这个集合中。
  • 创建AudioPatch对象的作用是,通知AudioFlinger让AudioHAL去设置播放设备。AudioPatch对象描述的是输入和输出的连接关系,包含两个成员变量:source和sink,它们都是AudioPort类型的。上一篇Android13音频子系统分析(一)---整体架构中介绍过,Device和OutputSream都是AudioPort类型的子类。
  • onNewAudioModulesAvailableInt()函数中并没有使用ProductStrategy来判断应该使用哪种播放设备,而是看当前的OutputSream支持的可用设备中,是否包含配置文件中配置的<defaultOutputDevice>,如果包含,就直接使用它作为播放设备,如果不包含,就从自己关联上的可用播放设备列表中,选择第一个作为播放设备。

1.3.4 AudioPolicyManager::updateDevicesAndOutputs()函数

updateDevicesAndOutputs()函数的代码调用流程如下:

AudioPolicyManager.cpp->updateDevicesAndOutputs()
    |-->Engine.cpp->updateDeviceSelectionCache()//遍历所有的ProductStrategy,找到它们目前应该选择的Device。然后保存到Engine::mDevicesForStrategies集合中。
        |-->Engine.cpp->getDevicesForProductStrategy()

            |-->Engine.cpp->remapStrategyFromContext()//调整设备选择策略。比如当处于通话或VoIP状态时,STRATEGY_MEDIA和STRATEGY_SONIFICATION都改为使用STRATEGY_PHONE对应的播放设备。也就是说通话时音乐播放的设备会改为与通话设备相同,比如听筒。
            
            |-->Engine.cpp->filterOutputDevicesForStrategy()//过滤掉一些可用的Device。比如通话场景下去掉A2DP设备。

            |-->Engine.cpp->getPreferredAvailableDevicesForProductStrategy()//查找上层AudioService设置的PreferredAvailableDevices。
                |-->EngineBase.cpp->getDevicesForRoleAndStrategy()//从EngineBase::ProductStrategyDevicesRoleMap集合中找到该strategy对应的所有devices,这个集合里的数据由AudioService设置。

            |-->Engine.cpp->getDevicesForStrategyInt()//只有当AudioService没有设置此ProductStrategy对应的PreferredDevices时,才会调用它。
									

        其中比较关键的是Engine::getDevicesForProductStrategy()函数。它定义了根据不同的场景如何选择合适播放设备的策略。整体的策略是:

  1. 先看框架层AudioService有没有设置当前ProductStrategy对应的PreferredDevices。如果设置了,就直接使用。这些PreferredDevices保存在EngineBase::ProductStrategyDevicesRoleMap集合中。
  2. 如果上层没有设置PreferredDevices,就通过Engine::getDevicesForStrategyInt()函数来进行播放设备的策略选择。
  3. 如果Engine::getDevicesForStrategyInt()函数也找不到合适的Device,就直接使用defaultOutputDevice。

可以看出,上层AudioService设置下来的PreferredDevices,优先级会高于Engine模块自己的策略。Engine::getDevicesForStrategyInt()函数中实现的主要策略如下:

  • 通话场景下(STRATEGY_PHONE):如果助听器(AUDIO_DEVICE_OUT_HEARING_AID)可用,  就使用它。助听器设备不可用,而可插拔的外设(比如有线耳机或无线蓝牙耳机)可用,就用可插拔的外设。外设也不可用,就用听筒(AUDIO_DEVICE_OUT_EARPIECE)。
  • 媒体播放场景下(STRATEGY_MEDIA):可插拔的外设可用,就用可插拔的外设。如果外设不可用,就用扬声器播放。当有线耳机和蓝牙耳机都连接上时,谁最后连接的就用谁。判断优先使用有线耳机还是蓝牙耳机的这部分代码是通过判断AUDIO_POLICY_FORCE_FOR_MEDIA是否设置了AUDIO_POLICY_FORCE_NO_BT_A2DP,设置了就优先使用有线耳机。上层AudioService会通过setForceUse()接口设置AUDIO_POLICY_FORCE_FOR_MEDIA的value。AudioService在监听到有线耳机连接上时,会设置为AUDIO_POLICY_FORCE_NO_BT_A2DP,而监听到有蓝牙设备连接上时,又会设置为AUDIO_POLICY_FORCE_NONE。所以,最终的逻辑是谁最后连接上的就用谁播放。
  • 铃声/闹钟播放场景下(STRATEGY_SONIFICATION):扬声器一定会出声,有外设连接上时,外设和扬声器都同时出声。其它的策略基本复用的是媒体播放场景的。因为case STRATEGY_SONIFICATION:的代码执行到分支最后时并没有break,所以可以复用媒体播放场景的策略。大家看代码时需要注意。

        以上就是AudioPolicyService的整个初始化流程,可以看出,AudioPolicyService模块的核心逻辑全部是在AudioPolicyManager子模块中实现的。总结一下:AudioPolicyService在初始化时,干的事就是通过解析配置文件,制定设备路由策略、加载音量曲线,然后根据配置文件中的信息通知AudioFlinger加载HwModule、创建Thread来打开IOStream。

二、AudioFlinger初始化

        AudioFlinger在其构造函数和onFirstRef()函数中,除了创建DevicesFactoryHalInterface和EffectsFactoryHalInterface对象,用于获取AudioHAL层的接口。就没有干其他重要的事情了。所以,AudioFlinger的初始化是比较简单的。但是,上面我们在分析AudioPolicyService初始化时,可以看到AudioPolicyService有通知AudioFlinger创建HwModule和PlaybackThread,它们对应的两个函数入口分别是AudioFlinger::loadHwModule()函数、AudioFlinger::openOutput()函数。

2.1 AudioFlinger::loadHwModule()函数

        loadHwModule()函数会根据AudioPolicyManager传递过来的name字符串,通知AudioHAL加载对应名称的so库,在HAL层,每个so库代表的就是不同的HwModule,也就是libaudiohal中描述的DeviceHalHidl对象。然后会将DeviceHalHidl对象保存到AudioHwDevice中,最后将AudioHwDevice对象保存AudioFlinger::mAudioHwDevs集合中,供后续的业务逻辑代码查找使用。代码调用流程如下:

AudioFlinger.cpp->loadHwModule()//AudioPolicyManager初始化时,会在onNewAudioModulesAvailableInt()函数中调用此接口
	|-->AudioFlinger.cpp->loadHwModule_l()
		|-->DevicesFactoryHalHidl.cpp->openDevice()//通知AudioHAL层打开虚拟device。AudioHAL会根据传入的name字符串,加载对应的so库。

			|-->DevicesFactory.cpp->openDevice()//通过Binder跨进程调用,接下来的代码都运行在AudioHAL进程中
				|-->DevicesFactory.cpp->loadAudioInterface()//AUDIO_HARDWARE_MODULE_ID在/hardware/libhardware/include/hardware/audio.h文件中定义,value为"audio"。
					|-->hardware.c->hw_get_module_by_class()//拼接对应so库的名称。so库的代码实现由SoC厂商提供。
						|-->hardware.c->load()//通过dlopen()加载这个so库。然后在so库中找到名称为HAL_MODULE_INFO_SYM的hw_module结构体。
					|-->audio.h->audio_hw_device_open()//调用加载的so库中,定义的audio_module.common.methods.open()函数。

其中,DevicesFactory.cpp源文件位于hardware/interfaces/audio/core/all-versions/default/目录中。

hardware.c源文件位于hardware/libhardware/目录中。

audio.h源文件位于hardware/libhardware/include/hardware/目录中。

AUDIO_HARDWARE_MODULE_ID在/hardware/libhardware/include/hardware/audio.h文件中定义,value为"audio"。

2.2 AudioFlinger::openOutput()函数

openOutput()函数会通过AudioHwDevice对象通知AudioHAL打开OutStream,对应的是libaudiohal中的StreamOutHalHidl,这个对象会被保存到AudioStreamOut中供AudioFlinger使用。最后,会根据不同的flag类型创建不同的PlaybackThread子类,并把它们统一保存到AudioFlinger::mPlaybackThreads集合中。代码调用流程如下:

AudioFlinger.cpp->openOutput()//AudioPolicyManager初始化时,会在onNewAudioModulesAvailableInt()函数中调用此接口
	|-->AudioFlinger.cpp->openOutput_l()//根据不同的flag创建不同的PlaybackThread对象。
		|-->AudioHwDevice.cpp->openOutputStream()//通知AudioHAL打开StreamOut,然后创建一个对应的AudioStreamOut对象。

        在PlaybackThread的onFirstRef()函数中,会调用父类Thread.h的run()函数。所以,当PlaybackThread的对象被创建时,它就会被为作为循环线程启动。然后此线程就会循环调用PlaybackThread::threadLoop()函数。所以,可以把threadLoop()函数看做是PlaybackThread的入口函数,它也是PlaybackThread的核心,主要的播放流程都在这里面实现的。当我分析到播放流程时,会再深入分析下此函数。

三、AudioService初始化

        AudioService运行在SystemServer进程中,由SystemServer.java负责创建,然后将其作为Binder服务添加到ServiceManager中,供AudioManager调用。它的初始化函数入口有两个:构造函数、systemReady()函数。AudioService的初始化工作内容,除了创建各个子模块比如AudioDeviceBroker、PlaybackActivityMonitor等,创建自己的循环消息处理线程以外,最主要的工作就是进行音量初始化。

AudioService会从系统属性中读取每个StreamType配置的最大音量等级,从SettingProvider数据库中读取已保存的当前正在使用的音量等级,然后通知AudioPolicyService去设置每个StreamType对应的最大音量等级,以及设置该StreamType包含的每类Device所对应使用的音量等级。

在详细分析整个初始化流程之前,我先介绍下AudioService.VolumeStreamState和AudioService.VolumeGroupState这两个内部类。它们是音量控制逻辑的核心地方。 

从上面这个类图中可以看出,这两个AudioService内部类的成员变量和对外提供的接口函数都很相似,有些函数连名称都是一样的,这就导致我们在走读跟踪代码时,容易看错,比如错把VolumeGroupState的applyAllVolumes()函数当成了VolumeStreamState的。大家在看代码时也要注意一下。一个简单的办法是看这个函数实现中用的哪把线程锁,比如VolumeStreamState.applyAllVolumes()肯定用的是VolumeStreamState.class,VolumeGroupState.applyAllVolumes()肯定用的是VolumeGroupState.class。这样从名称上就可以直接区别了。

那么这两个内部类有什么不同呢?VolumeStreamState代表的是一个StreamType所对应的音量等级。包括最小音量等级mIndexMin、最大音量等级mIndexMax、每种Device对应正在使用的音量等级mIndexMap,mIndexMap的key是Device类型,比如DEVICE_OUT_SPEAKER。也就是说VolumeStreamState类是基于StreamType来进行音量控制。需要注意的是mIndexMin、mIndexMax、mIndexMap这三个成员变量中保存的音量等级大小都会X10,放大十倍。因为音量等级是int型的,放大十倍来保存数值的目的是为了精确计算,更平滑的控制音量大小。VolumeStreamState最后在通知AudioPolicyService进行音量等级设置时,会加上5再除以10,类似四舍五入。而三个比较重要的数组AudioService.MIN_STREAM_VOLUME[]、AudioService.MAX_STREAM_VOLUME[]、AudioSystem.DEFAULT_STREAM_VOLUME[]中保存的数值是没有经过放大的,大家在修改代码时需要注意。VolumeGroupState中保存的音量等级数值也没有经过10倍放大。

VolumeGroupState代表的是一个VolumeGroup所对应的音量等级。因为在AudioPolicyService的配置中,一个VolumeGroup可以被多个不同的StreamType复用,也就是1:n的关系。所以理论上VolumeGroupState列表会比VolumeStreamState列表的个数少一些。但是实际配置文件中,StreamType和VolumeGroup是1:1的关系,所以两者其实都是基于StreamType在设置音量。区别只是VolumeGroupState提供了根据AudioAttributes进行音量设置的接口。主要是通过AudioManager的setVolumeIndexForAttributes()函数、getVolumeIndexForAttributes()函数。我全局搜索了这两个函数,发现并没有地方调用它们。所以,VolumeGroupState类在实际运行时,并没有被真正用到。

以下是音量初始化的代码流程:

AudioService.java->AudioService()
    |-->AudioProductStrategy.java->getAudioProductStrategies()
    |-->AudioProductStrategy.java->initializeAudioProductStrategies()
        |-->AudioSystem.cpp->listAudioProductStrategies()//调用AudioPolicyService的listAudioProductStrategies函数,获取ProductStrategies数据。从而读取各个StreamType对应的最小和最大音量等级

    |-->从系统属性中获取每种StreamType配置的最大音量等级和开机默认音量等级,分别保存到MAX_STREAM_VOLUME[]数组和DEFAULT_STREAM_VOLUME[]数组中。

    |-->AudioService.java->createAudioSystemThread()//创建并启动名为AudioService的循环消息处理线程

    |-->AudioService.java->updateStreamVolumeAlias()//根据平台不同,选择Stream别名的定义策略。比如TV电视会STREAM_VOLUME_ALIAS_TELEVISION,手机会使用STREAM_VOLUME_ALIAS_VOICE。

    |-->AudioService.java->onInitStreamsAndVolumes()//内部线程在处理MSG_INIT_STREAMS_VOLUMES消息时调用
        |-->AudioService.java->createStreamStates()//根据StreamType的数量,创建对应的VolumeStreamState对象,保存到mStreamStates数组中。
            |-->new VolumeStreamState()
                |-->AudioSystem.cpp->initStreamVolume()//通知AudioPolicyService设置最大和最小音量等级
                |-->VolumeStreamState.readSettings()//从SettingProvider中读取当前StreamType对应的各个device的默认音量等级,如果SettingProvider中没有配置,就使用AudioSystem.DEFAULT_STREAM_VOLUME[]数组中的配置。
            |-->AudioService.java->checkAllFixedVolumeDevices()//使用固定音量的Device,将其音量设置为最大。
            |-->AudioService.java->checkAllAliasStreamVolumes()
                 |-->VolumeStreamState.setAllIndexes()//拷贝当前StreamType对应别名的音量
                 |-->VolumeStreamState.applyAllVolumes()//设置当前streamType所有对应device的音量等级到AudioPolicyService中
                    |-->VolumeStreamState.setStreamVolumeIndex()
                        |-->AudioSystem.cpp->setStreamVolumeIndexAS(mStreamType, index, device)
            
        |-->AudioService.java->initVolumeGroupStates()//初始化VolumeGroupState对象

最后,介绍一下StreamVolumeAlias,它的作用让一种StreamType可以复用另外一种StreamType的音量等级数据。通过一个数组来表示它们复用的关联关系。因为有了这个功能,导致AudioService的音量设置相关代码中,可以大量看到转换StreamType的地方,增加了一点点阅读代码的难度。以下是手机采用的StreamType复用的例子,可以看出,STREAM_NOTIFICATION和STREAM_SYSTEM都是复用的STREAM_RING的音量等级数据。

猜你喜欢

转载自blog.csdn.net/weixin_41004543/article/details/132887935
今日推荐