4.1 AudioPolicy的诞生

AudioPolicyService是Android音频系统的两大服务之一,另一个服务是AudioFlinger,这两大服务都在系统启动时有MediaSever加载,代码在framework/base/media/MediaServer/Main_MediaServer中。

  1. int main(int argc, char** argv)
  2. {
  3. sp<ProcessState> proc(ProcessState::self());
  4. sp<IServiceManager> sm = defaultServiceManager();
  5. //先创建AF
  6. AudioFlinger::instantiate();
  7. //再创建APS
  8. AudioPolicyService::instantiate();
  9. ProcessState::self()->startThreadPool();
  10. IPCThreadState::self()->joinThreadPool();
  11. }

4.1.1 new AudioFlinger

  1. AudioFlinger::AudioFlinger()
  2. : BnAudioFlinger(),//基类构造函数
  3. mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextThreadId(0)
  4. {
  5. ....
  6. mHardwareStatus = AUDIO_HW_IDLE;
  7. mAudioHardware = AudioHardwareInterface::create();
  8. mHardwareStatus = AUDIO_HW_INIT;
  9. ....
  10. if (mAudioHardware->initCheck() == NO_ERROR) {
  11. setMode(AudioSystem::MODE_NORMAL);
  12. setMasterVolume(1.0f);
  13. setMasterMute(false);
  14. }
  15. }

感觉上,AudioFlinger的构造函数就是创建了一个最重要的AudioHardWare的HAL代表。注意整个系统就这一个AudioHardware了。也就是说,不管是线控耳机,蓝牙耳机,麦克,外放等等,最后都会由这一个HAL统一管理。

4.1.2 new AudioPolicyService

  1. AudioPolicyService::AudioPolicyService()
  2. : BnAudioPolicyService() , mpPolicyManager(NULL)
  3. {
  4. char value[PROPERTY_VALUE_MAX];
  5. // start tone playback threadmTonePlaybackThread = new AudioCommandThread(String8("ApmTone"), this);// start audio commands threadmAudioCommandThread = new AudioCommandThread(String8("ApmAudio"), this);// start output activity command threadmOutputCommandThread = new AudioCommandThread(String8("ApmOutput"), this);
  6. rc = mpAudioPolicyDev->create_audio_policy(mpAudioPolicyDev, &aps_ops, this,&mpAudioPolicy);
         rc = mpAudioPolicy->init_check(mpAudioPolicy);} 

构造函数中调用了policy_hal中的create_audio_policy函数和init_check函数,create_audio_policy函数的目的是设置回调函数并且调用createAudioPolicyManager函数创建AudioPolicyManager(apm)的实例。init_check函数调用的apm的init_check函数,即是AudioPolicyManagerBase的init_check函数。不同厂商还可以实现自己的AudioPolicyManager,这样做的好处就是把server断和client端分离,减少代码的耦合度。

4.1.3 AudioPolicyCompatClient

为了符合C/S的架构,AudioPolicy也遵循了该架构,这里就是AudioPolicy的client端,它实际调用的还是server端的接口函数。

int create_legacy_ap(){

......

lap->service_client = new AudioPolicyCompatClient(aps_ops, service);

lap->apm = createAudioPolicyManager(lap->service_client);

}

该函数首先创建一个client对象,再把client对象传给audiopolicy的server端。client调用的接口函数最终会调用server的接口函数。

4.1.4 AudioPolicyManagerBase

构造函数就会使用mpClientInterface来访问AudioPolicyService。

AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clientInterface)

{

......

for (size_t i = 0; i < mHwModules.size(); i++) {
        mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->mName);
        if (mHwModules[i]->mHandle == 0) {
            ALOGW("could not open HW module %s", mHwModules[i]->mName);
            continue;
        }
     ......

}

4.2 AudioPolicyServie

4.2.1 AudioPolicyService主要完成:
1、JAVA应用层通过JNI,经由IAudioPolicyService接口,访问AudioPolicyService提供的服务

2、输入输出设备的连接状态

3、系统的音频策略(strategy)的切换

4、音量/音频参数的设置

4.2.2 AudioPolicyService的构成

1、AudioPolicyService继承了IAudioPolicyService接口,这样AudioPolicyService就可以基于Android的Binder机制,向外部提供服务;

2、AudioPolicyService同时也继承了AudioPolicyClientInterface类,它有一个AudioPolicyInterface类的成员指针mpPolicyManager,实际上就是指向了AudioPolicyManager;

3、AudioPolicyManager类继承了AudioPolicyInterface类以便向AudioPolicyService提供服务,反过来同时还有一个AudioPolicyClientInterface指针,该指针在构造函数中被初始化,指向了AudioPolicyService,实际上,AudioPolicyService是通过成员指针mpPolicyManager访问AudioPolicyManager,而AudioPolicyManager则通过AudioPolicyClientInterface(mpClientInterface)访问AudioPolicyService;

4、AudioPolicyService有一个内部线程类AudioCommandThread,顾名思义,所有的命令(音量控制,输入、输出的切换等)最终都会在该线程中排队执行;

4.3 AudioPolicyManager

AudioPolicyService的很大一部分管理工作都是在AudioPolicyManager中完成的。包括音量管理,音频策略(strategy)管理,输入输出设备管理。

4.3.1 输入输出设备管理

音频系统为音频设备定义了一个枚举:AudioSystem::audio_devices,例如:DEVICE_OUT_SPEAKER,DEVICE_OUT_WIRED_HEADPHONE,DEVICE_OUT_BLUETOOTH_A2DP,DEVICE_IN_BUILTIN_MIC,DEVICE_IN_VOICE_CALL等等,每一个枚举值其实对应一个32bit整数的某一个位,所以这些值是可以进行位或操作的,例如我希望同时打开扬声器和耳机,那么可以这样:

newDevice = DEVICE_OUT_SPEAKER | DEVICE_OUT_WIRED_HEADPHONE;

setOutputDevice(mHardwareOutput, newDevice);

AudioPolicyManager中有两个成员变量:mAvailableOutputDevices和mAvailableInputDevices,他们记录了当前可用的输入和输出设备,当系统检测到耳机或者蓝牙已连接好时,会调用AudioPolicyManager的成员函数:

status_t AudioPolicyManager::setDeviceConnectionState(AudioSystem::audio_devices device, AudioSystem::device_connection_state state,const char *device_address)

该函数根据传入的device值和state(DEVICE_STATE_AVAILABLE/DEVICE_STATE_UNAVAILABLE)设置mAvailableOutputDevices或者mAvailableInputDevices,然后选择相应的输入或者输出设备。

其他一些相关的函数:

1、setForceUse()  设置某种场合强制使用某一设备,例如setForceUse(FOR_MEDIA, FORCE_SPEAKER)会在播放音乐时打开扬声器

2、startOutput()/stopOutput()

3、startInput()/stopInput()

4.3.2 音量管理

AudioPolicyManager提供了一下几个与音量相关的函数:

1、initStreamVolume(AudioSystem::stream_type stream, int indexMin, int indexMax)

2、setStreamVolumeIndex(AudioSystem::stream_type stream, int index)

3、getStreamVolumeIndex(AudioSystem::stream_type stream)

AudioService.java中定义了每一种音频流的最大音量级别:

/** @hide Maximum volume index values for audio streams */
    private int[] MAX_STREAM_VOLUME = new int[] {
        5,  // STREAM_VOICE_CALL
        7,  // STREAM_SYSTEM
        7,  // STREAM_RING
        15, // STREAM_MUSIC
        7,  // STREAM_ALARM
        7,  // STREAM_NOTIFICATION
        15, // STREAM_BLUETOOTH_SCO
        7,  // STREAM_SYSTEM_ENFORCED
        15, // STREAM_DTMF
        15  // STREAM_TTS
    };

由此可见,电话铃声可以有7个级别的音量,而音乐则可以有15个音量级别,java的代码通过jni,最后调用AudioPolicyManager的initStreamVolume(),把这个数组的内容传入AudioPolicyManager中,这样AudioPolicyManager也就记住了每一个音频流的音量级别。应用程序可以调用setStreamVolumeIndex设置各个音频流的音量级别,setStreamVolumeIndex会把这个整数的音量级别转化为适合人耳的对数级别,然后通过AudioPolicyService的AudioCommandThread,最终会将设置应用到AudioFlinger的相应的Track中。

4.3.3 音频策略管理

我想首先要搞清楚stream_type,device,strategy三者之间的关系:

1、AudioSystem::stream_type  音频流的类型,一共有10种类型

2、AudioSystem::audio_devices  音频输入输出设备,每一个bit代表一种设备,见前面的说明

3、AudioPolicyManager::routing_strategy 音频路由策略,可以有4种策略

getStrategy(stream_type)根据stream type,返回对应的routing strategy值,getDeviceForStrategy()则是根据routing strategy,返回可用的device。Android把10种stream type归纳为4种路由策略,然后根据路由策略决定具体的输出设备。

4.3.4 成员变量mOutputs

KeyedVector<audio_io_handle_t, AudioOutputDescriptor *> mOutputs;   // list of output descriptors

这是AudioPolocyManager用来管理输出的键值对向量(数组),通常AudioPolocyManager会打开3个输出句柄(audio_io_handle_t),关于audio_io_handle_t,它实际上就是AudioFlinger中某个PlaybackTread的ID。这3个句柄分别是:

  • mHardwareOutput            // hardware output handler
  • mA2dpOutput                   // A2DP output handler
  • mDuplicatedOutput          // duplicated output handler: outputs to hardware and A2DP

可以通过startOutput()把某一个stream type放入到相应的输出中。

4.3.5 popCount()

这个函数主要用来计算device变量中有多少个非0位(计算32位数种1的个数),例如该函数返回2,代表同时有两个device要处理。之所以特别介绍它,是因为这个函数的实现很有意思:

uint32_t AudioSystem::popCount(uint32_t u)
{
    u = ((u&0x55555555) + ((u>>1)&0x55555555));
    u = ((u&0x33333333) + ((u>>2)&0x33333333));
    u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f));
    u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff));
    u = ( u&0x0000ffff) + (u>>16);
    return u;
}

4.3.6 AudioCommandThread

这是AudioPolicyService中的一个线程,主要用于处理音频设置相关的命令。包括:

  • START_TONE
  • STOP_TONE
  • SET_VOLUME
  • SET_PARAMETERS
  • SET_VOICE_VOLUME

每种命令的参数有相应的包装:

  • class ToneData
  • class VolumeData
  • class ParametersData
  • class VoiceVolumeData

START_TONE/STOP_TONE:播放电话系统中常用的特殊音调,例如:TONE_DTMF_0,TONE_SUP_BUSY等等。

SET_VOLUME:最终会调用AudioFlinger进行音量设置

SET_VOICE_VOLUME:最终会调用AudioFlinger进行电话音量设置

SET_PARAMETERS:通过一个KeyValuePairs形式的字符串进行参数设置,KeyValuePairs的格式可以这样:

  • "sampling_rate=44100"
  • "channels=2"
  • "sampling_rate=44100;channels=2"     // 组合形式

这些KeyValuePairs可以通过AudioPolicyService的成员函数setParameters()传入。

4.3 AudioPolicy总结

1、AudioPolicyService才是真正调用AudioFlinger的地方,Audio_poliy_hal、AudioPolicyManagerBase最终都会绕到AudioPolicyService里面去。

2、AduioPolicyService调用AudioFlinger里面的函数,是通过Binder机制,即调用接口IAudioFlinger接口。

3、AudioPolicyService只提供服务给AudioSystem.cpp,通过Binder接口调用。其他类不可以直接调用AudioPolicyService类,只能调用AudioSystem里面的方法间接调用AudioPolicyService。

Android音频系统之四AudioPolicy相关推荐

  1. android音频系统之AudioTrack的使用

    今天,简单讲讲  AudioTrack的使用. 1.Android AudioTrack简介 在android中播放声音可以用MediaPlayer和AudioTrack两种方案的,但是两种方案是 ...

  2. Android 音频系统:从 AudioTrack 到 AudioFlinger(全)

    Android 音频框架概述 Audio 是整个 Android 平台非常重要的一个组成部分,负责音频数据的采集和输出.音频流的控制.音频设备的管理.音量调节等,主要包括如下部分: Audio App ...

  3. android音频系统(4):AudioService之音量管理

    前言:AudioService这个系统服务包含或者使用了几乎所有与音频有关的内容,AudioService是音频系统在java层的大本营: android音频系统,分为两个部分:数据流和策略: 数据流 ...

  4. Android音频系统的改进设想和展望 PulseAudio介绍

    http://www.soomal.com/doc/10100002871.htm 在这里先说明,本人并没有仔细地去看Android和PulseAudio的音频具体源代码和实现,欢迎指正. 从硬件用料 ...

  5. 深度剖析 Android音频系统解析与改进

    导读:Android是用了一个Google自己开发的中间层API来让APP和声音驱动(ALSA或者HAL封闭驱动)通信的.在早期,它是个ALSA的插件:现在则命名为AudioFlinger.但是安卓音 ...

  6. android 4.0 电话录音,ANDROID音频系统散记之四:4.0音频系统HAL初探

    昨天(2011-11-15)发布了Android4.0的源码,今天download下来,开始挺进4.0时代.简单看了一下,发现音频系统方面与2.3的有较多地方不同,下面逐一描述. 一.代码模块位置 1 ...

  7. ANDROID音频系统散记之四:4.0音频系统HAL初探

    昨天(2011-11-15)发布了Android4.0的源码,今天download下来,开始挺进4.0时代.简单看了一下,发现音频系统方面与2.3的有较多地方不同,下面逐一描述. 一.代码模块位置 1 ...

  8. Android音频系统之AudioPolicyService

    地址:http://blog.csdn.net/edmond999/article/details/18599327 1.1 AudioPolicy Service 在AudioFlinger小节,我 ...

  9. android音频系统(5):AudioService之音频焦点

    前言:上一节我们分析了AudioService对音量的管理,这一节来看下AudioService对音频焦点的处理,也就是音频系统中的AudioFocus机制,它用来处理多个音频不合理的同时播放的糟糕后 ...

最新文章

  1. PHP autoload机制详解
  2. 深度神经网络中处理数据和训练模型的一些技巧
  3. 机器学习-Kmeans聚类
  4. Linux mount 修改文件系统的读写属性
  5. 部署在ABAP Netweaver上的UI5应用,UI5库那些JavaScript的具体位置
  6. python常见内置函数
  7. win10,配置环境变量时系统环境变量和用户环境变量的优先级
  8. python 退出_如果读完这篇文章不能让你入门Python,那我将永久退出编程界
  9. php preg_match_all匹配正则,字符串过长时出错
  10. 在JSP中应用JavaBean
  11. [转载] Python中生成器和迭代器的区别
  12. 排序算法专题-插入排序
  13. 计算机windows试题,计算机基础《Windows》考试试题
  14. js延时函数--setTimeout
  15. JVM上篇:内存与垃圾回收
  16. 四川山海蓝图抖音上热门的技巧
  17. 计算机内存一代,内存条一代二代三代的区别
  18. 物联网嵌入式学习路线
  19. 计算机内存条能装几个,4G内存条和2G内存条能不能装到一个电脑上?
  20. JavaCV开发详解之1:调用本机摄像头并预览摄像头图像画面视频(建议使用javaCV最新版本)

热门文章

  1. android 自定义圆形进度条拖动样式,android自定义圆形进度条
  2. 【初识C语言】从头到尾了解C语言这一篇足矣
  3. 黄土高原主要是什么树木
  4. 利用osg::ClipPlane 对节点进行多边形裁切
  5. 一杯严选+荣登一品+美私奢玩@HiFi++中国式高阶生活美学的海外文化节
  6. html word 编辑表格,在Word文档中运用编辑表格的7个技巧
  7. 解决IMP-00058和IMP-00000
  8. ffmpeg开发之旅(3):AAC编码格式分析与MP4文件封装(MediaCodec+MediaMuxer)
  9. 设计模式-七大原则(图解一目了然)
  10. 1核2G3M,系统盘40G,流量500G/月,83一年