在创建一个AudioPolicyService对象时,主要是: 1. 创建两个AudioCommand线程,一个线程用于Tone的播放,另一个用于声音的音量及其它参数设置; 2.创建音频策略管理器(AudioPolicyManager)。Android Frameworks为音频策略管理器定义了统一的接口--AudioPolicyInterface,并提供一个缺省的音频管理器--AudioPolicyManagerBase,它为运行在模拟器上Android所使用,也可以使用宏激活该通用管理器。不同的硬件厂商,可以编写一个继承AudioPolicyInterface的子类,针对自己的硬件平台,实现自己的音频策略管理。 在音频策略服务(AudioPolicyService)中,会根据一定的条件去判断创建何种音频策略管理器: AudioPolicyService::AudioPolicyService() #if (defined GENERIC_AUDIO) || (defined AUDIO_POLICY_TEST) // load properties 下图反映了几个类之间的关系:AudioPolicyService继承自BnAudioPolicyService,所以它提供了IAudioPolicyService接口的真正实现,可以通过该接口跨进程调用到它。AudioPolicyService也继承了AudioPolicyClientInterface,所以它实现了该抽象类的接口,其实现是通过AudioSystem调用到AudioFlinger(下图AudioPolicyService到AudioFlinger的虚线所示)。如上面代码所示,在创建AudioPolicyService时,会创建一个音频策略管理器,如Android默认的管理器AudioPolicyManagerBase,也可能创建的是硬件平台厂家提供的音频管理器,这些管理器实现了AudioPolicyInterface接口。在创建音频管理器时,将this指针传递给了它,意味着音频管理器可以通过AudioPolicyClientInterface接口指针(图中策略管理器到AudioPolicyClientInterface的虚线)来使用AudioPolicyService,进而使用AudioFlinger。
音频策略管理器(Audio Policy Manager) 音频策略管理器用于管理声音的输入输出路由,它决定各种类型的声音(即流类型)优先送往系统中的哪种输出设备,或优先采用哪种输入设备进行声音的采样。如手机连有蓝牙耳机或耳机(HeadPhone)时,将优先使用它们作为输入输出设备。在Android中,有一个通用实现:类AudioPolicyManagerBase。硬件平台厂家往往需要实现自己的音频策略管理器,所有的重新实现必继承抽象类AudioPolicyInterface,该继承类定义了统一的接口函数。继承自该抽象类的通用实现AudioPolicyManagerBase位于文件frameworks/base/services/audioflinger/AudioPolicyManagerBase.cpp中。 在进行播放时,需使用策略管理器的getOutput函数去获得一个音频输入输出句柄audio_io_handle_t。这个句柄用来标识策略管理器中使用的一个数据结构:音频输出描述符AudioOutputDescriptor。一个描述符对应着一次音频输出,由输出句柄标识。音频输出描述符包含了某音频输出对应的输出设备、音量、格式、声道、采样率等信息。在策略管理器中,也维护着句柄和描述符的映射表: KeyedVector<audio_io_handle_t, AudioOutputDescriptor *> mOutputs; 音频输入输出句柄audio_io_handle_t,实际上是一个整型数,是在AduioFlinger打开输出(openOutput)时递增分配一个整型id号,用于标示新创建的播放线程(DirectOutputThread或MixerThread)。这个id号和新创建的线程作为数据对添加到向量表mPlaybackThreads中。AudioFlinger中维护的播放线程向量表如下,由句柄这个id号标识: DefaultKeyedVector< int, sp<PlaybackThread> > mPlaybackThreads; 因此,在策略管理中,可以由句柄得到对应的音频输出描述符,进而可以得到对应的音频相关信息和输出设备。在AudioFlinger中,可以由句柄得到对应的播放线程(该线程用于将音频数据送往HAL音频硬件)。 在Android中,将声音区分为不同的流类型。不同的流类型往往使用不同的输入输出设备进行输出,这就是音频策略。流类型由AudioSystem统一定义,但音频策略由平台实现者定义。因不同的平台厂商往往有自己的输入输出设备,音频的输入输出与这些设备有很大的相关性。因此,音频策略由平台厂商定义。在通用的实现AudioPolicyManagerBase中,定义有4种音频策略类型: enum routing_strategy { 根据流类型(Stream Type),应该可以得到对应的音频输入输出策略,这是由成员函数getStrategyForStream(AudioPolicyInterface中定义的接口之一)来实现。在通用实现AudioPolicyManagerBase中,由成员函数getStrategy真正去完成该功能。该函数实现的对应关系如下表:
第一栏是流的类型,第二栏是音频策略。从表中可以看出,某些流可以使用相同的音频策略进行输出或输入。 通过流确定了策略之后,就可以确定输入输出设备。在通常情况下,一种策略又决定着声音何种输入输出设备。 这由函数AudioPolicyManagerBase::getDeviceForStrategy来实现:
有时,我们不希望策略管理器选定的设备,而希望自己选择输入输出设备,在SDK的API中,提供了两个函数来为通话状态强制选择扬声器和蓝牙设备,这两个函数API是:android.media.AudioManager的setSpeakerphoneOn和setBluetoothScoOn。它们为通话状态(AudioSystem.FOR_COMMUNICATION)强制指定语音输入和输出设备。这两个API函数调用顺序如下:android.media.AudioManager->android.media.AudioService->android.media.AudioSystem->JNI层(文件android_media_AudioSystem.cpp)->AudioSystem-> AudioPolicyService->AudioPolicyManagerBase::setForceUse。 通过上述调用后,函数setForceUse将记录强制使用的设备,以优先使用。下表第一栏是四种场景类型,第二栏是可以强制使用的语音输入输出设备:
更多的强制选择,可以修改setForceUse的对应检查后,然后依据自己的代码所在的层次,参照对setForceUse的调用层次,调用适当的函数。
对于各种输入输出设备是否可用,如蓝牙耳机或线控耳机是否连接上,则是在Java层的android.media.AudioSystem中进行检测处理。当这些外设连接状态发生变化时,对应的模块会广播发送Intent,而android.media.AudioSystem中的AudioServiceBroadcastReceiver会接收到这些Intent,从而判断出设备状态变化,通过如下调用顺序来修可用IO设备列表:android.media.AudioSystem->JNI层 -> AudioSystem-> AudioPolicyService -> AudioPolicyManagerBase的setDeviceConnectionState。
创建AudioPolicyManagerBase时,会在其构造函数里
mpClientInterface = clientInterface;//指向AudioPolicyService的指针 for (int i = 0; i < AudioSystem::NUM_FORCE_USE; i++) { // devices available by default are speaker, ear piece and microphone #ifdef WITH_A2DP//一般情况下A2DP是打开的 // open hardware output if (mHardwareOutput == 0) {//失败 从上面的代码看出,在创建音频管理器的初始时刻,就会打开一个默认的输出,这个输出句柄赋值给mHardwareOutput,并添加到对应的列表中。
可以使用函数setOutputDevice为输出句柄(output)指定输出设备: void AudioPolicyManagerBase::setOutputDevice(audio_io_handle_t output, uint32_t device, bool force, int delayMs) 它首先检查是复制输出,是否是A2DP输出,然后调用mpClientInterface(实际调用到AudioFlinger)的setParameters来设置输出设备。还要将输出设备信息,更新到句柄output对应的输出描述符中。
获取音频IO句柄 audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type stream, uint32_t samplingRate, uint32_t format, uint32_t channels, AudioSystem::output_flags flags) 该函数根据steam类型得到strategy,再进而得到输出设备,然后创建一个输出描述符AudioOutputDescriptor,储存相关信息,最后将句柄和描述符添加到策略管理器维护的映射表中。注意:句柄的获取实际调用的是mpClientInterface的openOutput(实际调用到AudioFlinger的openOutput去准备播放线程进行播放输出)。
开始输出 status_t AudioPolicyManagerBase::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream, int session) 主要是调用setOutputDevice为ouput句柄指定输出设备,最后为其设定流对应的音量
主要是调用setOutputDevice为ouput句柄恢复为默认的输出设备 status_t AudioPolicyManagerBase::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream, int session) 将输出 获得输入句柄 audio_io_handle_t AudioPolicyManagerBase::getInput(int inputSource, uint32_t samplingRate, uint32_t format, uint32_t channels, AudioSystem::audio_in_acoustics acoustics, AudioSystem::audio_input_clients *inputClientId)
开始输入 status_t AudioPolicyManagerBase::startInput(audio_io_handle_t input) 通过输入句柄得到对应的输入描述符,然后通过mpClientInterface(实际调用到AudioFlinger)的setParameters将AudioParameter::keyRouting,inputDesc->mDevice,AudioParameter::keyInputSource,inputDesc->mInputSource
停止输入 status_t AudioPolicyManagerBase::stopInput(audio_io_handle_t input) 类似于输入,通过setParameters将AudioParameter::keyRouting对应的值修改为0 |
|