zoukankan      html  css  js  c++  java
  • 声音、音频Android音频系统之AudioPolicyServiceby小雨

    第一次发帖

        

    1.1 AudioPolicy Service

        在AudioFlinger节小,我们反复强调它只是策略的执行者,而AudioPolicyService则是策略的制订者。这类分离式方有效地降低了全部统系的藕合性,而且为各个模块独立展扩能功供给了障保。

        

    1.1.1 AudioPolicyService概述

        汉语中有很多与策略有联关的语俗,比如“宜制地因”、“体具问题体具析分”;战役中只遵照书兵制订战术的行为也被我们称为是“空言无补”、死读书。这些都诉告我们,解了策略的执行环境是非常重要的,只有清晰地界定出“问题是什么”,才能对症下药的制订出准确的Policy来决解问题。

        Android统系中声音的类种有很多种,体具类分如下所示:

        

        /*AudioManager.java*/   

        public static final intSTREAM_VOICE_CALL = 0; /* 通话声音*/

        public static final intSTREAM_SYSTEM = 1; /* 统系声音*/

        public static final int STREAM_RING = 2; /* 电话铃声和短信提示 */   

        public static final intSTREAM_MUSIC = 3; /* 音乐播放 */   

        public static final intSTREAM_ALARM = 4; /* 铃闹 */   

    public static final intSTREAM_NOTIFICATION = 5; /* 通知声音 */

     

        /*上面几个是隐藏型类,不对层上应用开放*/

        public static final intSTREAM_BLUETOOTH_SCO = 6; /*当连接蓝牙时的通话*/   

    public static final intSTREAM_SYSTEM_ENFORCED = 7; /* 强制的统系声音,比如有的国度强制求要

                                                       摄像头照拍时有声音,以止防偷拍*/  

        public static final intSTREAM_DTMF = 8; /* DTMF声音 */

        public static final intSTREAM_TTS = 9; /* 即text tospeech (TTS) */

        针对这么多型类的音频,AudioPolicyService少至面临着如下几个问题:

        l  上述型类的声音须要输出到哪些对应的件硬设备

        比如一部典范的手机,它既有听筒、耳机口接,还有蓝牙设备。假设默许情况下播放音乐是通过听筒喇叭输出的,那么当户用入插耳机时,这个策略就会转变——从耳机输出,而不再是听筒;又比如在呆板插着耳机时,播放音乐不该应从喇叭输出,但是当有来电铃声时,就须要同时从喇叭和耳机输出音频。这些“音频策略”的制订,主导者就是AudioPolicyService

        l  声音的由路策略

        如果把一个音乐播放实例(比如用MediaPlayer播放一首SD卡中的歌曲)比作源IP,那么上一步中找到的音频播放设备就是目标IP。在TCP/IP系体中,从源IP终究达到目标IP常通须要经过多少个由路器节点,由各由路器根据定一的算法来定决下一个匹配的节点是什么,从而制订出一条最好的由路路径,如下图所示:

        

     

        

        图 13‑16 由路器示意图

        AudioPolicyService所要决解的问题与由路器相似。因为统系中极可能存在多个audiointerface,个一每audio interface包含多少output,而个每output又同时持支多少种音频设备,这就意味着从播放实例到终端设备,须要经过audiointerface和output的择选,我们称之为AudioPolicyService的由路能功。

        l  每种型类音频的音量节调

        不同型类的音频,其音量的可节调范围是不一样的,比如有的是0-15,而有的则是1-20。而且它们的默许值也是有别差的,我们看AudioManager中的义定:

        

        public static final int[]  DEFAULT_STREAM_VOLUME = new int[] {

            4,  // STREAM_VOICE_CALL

            7,  // STREAM_SYSTEM

            5,  // STREAM_RING

            11, // STREAM_MUSIC

            6,  // STREAM_ALARM

            5,  // STREAM_NOTIFICATION

            7,  // STREAM_BLUETOOTH_SCO

            7,  // STREAM_SYSTEM_ENFORCED

            11, // STREAM_DTMF

            11  // STREAM_TTS

        };

        音量的节调分部面后我们有专门的节小来分析。

        为了让大家对AudioPolicyService有个性感的意识,我们以下图来象形地表现它与AudioTrack及AudioFlinger间的系关:

        

     

        

        图 13‑17 AudioPolicyService与AudioTrack和AudioFlinger的系关

        这个图中的素元包含AudioPolicyService、AudioTrack、AudioFlinger、PlaybackThread以及两音频设备(喇叭、耳机)。它们之间的系关如下(特别注意,本例的目标只是说明这些素元的系关,不并代表图中的策略就是Android统系所采取的):

        l  一个PlaybackThread的输出对应了一种设备

        比如图中有两个设备,就有两个PlaybackThread与之对应。边左的Thread终究音混后输出到喇叭,而右侧的则输出到耳机

        l  在特定的时光,一同型类音频对应的输出设备是一统的

        也就是说,如果以后STREAM_MUSIC对应的是喇叭,那么所有该型类的音频都市输出到喇叭。结合上一点,我们还可以得出一个论断,即一同型类音频对应的PlaybackThread也是一样的

        l  AudioPolicyService起到了由路的用作

        AudioPolicyService在全部择选程过中的用作有点相似于网络由路器,它有权定决某一个AudioTrack所生产的音频流终究会走向哪个设备,就像由路器可以根据定一的算法来定决发送者的包该应传递给哪个节点一样

        接下来我们从三个方面来解了AudioPolicyService。

        首先,从启动程过来看AudioPolicyService的工作式方。

        其次,我们结合上面的系关图详细析分AudioPolicyService是如何实现“由路能功”的。

        最后,我们来析分Android统系下默许的“由路策略”是怎样的。

        

    1.1.2 AudioPolicyService的启动程过

        还记得面前我们在析分AudioFlinger的启动时,经曾看到过AudioPolicyService的影子吗?没错,它和AudioFlinger是驻留在一同个程序中的,如下所示:

        

    /*frameworks/av/media/mediaserver/Main_mediaserver.cpp*/

    int main(int argc, char** argv)

    {   …

       AudioFlinger::instantiate();

        …

       AudioPolicyService::instantiate();

       ProcessState::self()->startThreadPool();

       IPCThreadState::self()->joinThreadPool();

    }

        因而从理论上来讲,AudioFlinger和AudioPolicyService是可以直接行进函数调用的。不过实际上它们仍然采取标准的Binder行进通信。

        AudioPolicyService的启动式方和AudioFlinger也是相似的,我们这里就不赘述,直接来看它的构造函数:

        

    AudioPolicyService::AudioPolicyService()

        : BnAudioPolicyService() ,mpAudioPolicyDev(NULL) , mpAudioPolicy(NULL)

    {

        charvalue[PROPERTY_VALUE_MAX];

        const struct hw_module_t*module;

        int forced_val;

        int rc;

        …

        rc =hw_get_module(AUDIO_POLICY_HARDWARE_MODULE_ID, &module);//Step 1.

        …

        rc =audio_policy_dev_open(module, &mpAudioPolicyDev);//Step 2.

        …

        rc =mpAudioPolicyDev->create_audio_policy(mpAudioPolicyDev, &aps_ops, this,

                                                   &mpAudioPolicy);//Step3.

        …

        rc =mpAudioPolicy->init_check(mpAudioPolicy); //Step 4.

    //Step 5

       property_get("ro.camera.sound.forced", value, "0");

        forced_val = strtol(value,NULL, 0);

    mpAudioPolicy->set_can_mute_enforced_audible(mpAudioPolicy,!forced_val);

    //Step 6.

        if(access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) {

           loadPreProcessorConfig(AUDIO_EFFECT_VENDOR_CONFIG_FILE);

        } else if(access(AUDIO_EFFECT_DEFAULT_CONFIG_FILE, R_OK) == 0) {

            loadPreProcessorConfig(AUDIO_EFFECT_DEFAULT_CONFIG_FILE);

        }

    }

        我们将上述代码段分为6个步骤来讲解。

        Step1@ AudioPolicyService::AudioPolicyService. 得到Audio Policy的hw_module_t,原生态统系中Policy的实现有两个地方,即Audio_policy.c和Audio_policy_hal.cpp,默许情况下统系择选的是后者(对应的库是libaudiopolicy_legacy)

        Step2@ AudioPolicyService::AudioPolicyService. 通过上一步得到的hw_module_t打开Audio Policy设备(这不并是一个传统意义的件硬设备,而是把Policy虚拟成了一种设备。这样子的实现式方让音频件硬厂商在制订自己的音频策略时多了不少灵活性)。原生态代码中audio_policy_dev_open调用的是legacy_ap_dev_open@Audio_policy_hal.cpp,终究生成的Policy Device实现是legacy_ap_device

        Step 3@ AudioPolicyService::AudioPolicyService. 通过上述的Audio Policy设备来生产一个策略,其对应的体具实现方法是create_legacy_ap@Audio_policy_hal.cpp。这个函数首先生成的一个legacy_audio_policy@Audio_policy_hal.cpp,而mpAudioPolicy对应的则是legacy_audio_policy::policy。除此之外,legacy_audio_policy还包含如下重要成员变量:

        struct legacy_audio_policy {

        structaudio_policy policy;

        void *service;

        structaudio_policy_service_ops *aps_ops;

       AudioPolicyCompatClient *service_client;

       AudioPolicyInterface *apm;

        };

        其中aps_ops是由AudioPolicyService供给的函数指针(aps_ops),这里面的函数是AudioPolicyService与外界沟通的口接,面后还会经常遇到。

        最后一个apm是AudioPolicyManager的简写,AudioPolicyInterface是其基类,apm在原生态实现上是一个AudioPolicyManagerDefault对象,它是在create_legacy_ap中创建的:

        

    static int create_legacy_ap(const struct audio_policy_device*device,

                                structaudio_policy_service_ops *aps_ops,

                               void *service,

                               struct audio_policy **ap)

    {

        struct legacy_audio_policy*lap;

                    …

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

    …}

        函数createAudioPolicyManager默许情况下对应的是AudioPolicyManagerDefault.cpp中的实现,所以它将返回一个AudioPolicyManagerDefault。

        是不是觉得Policy相关的类越来越多了?那为什么须要这么多类呢?我们先来看一下它们之间的系关:

        

        图 13‑18 Audio Policy相关类的系关

        看起来很复杂,其实概况起来就以下几点:

        l  AudioPolicyService持有的只是一个相似于口接类的对象,即audio_policy。换句话说,AudioPolicyService是一个“壳”,而audio_policy则是一个符合求要的插件。插件与壳之间的口接是固定不变的,而内部实现却可以根据厂商自己的需求来做

        l  我们知道,audio_policy实际上是一个C语言中的struct型类,内部包含了各种函数指针,比如get_output、start_output等等。这些函数指针在初始化时,须要指向体具的函数实现,这就是Audio_policy_hal中的ap_get_output、ap_start_output等等

        l  上面提到的各数据型类更多的只是一个“壳”,而真正的实现者是AudioPolicyManager。与此相关的又有三个类:AudioPolicyInterface是它们的基类,AudioPolicyManagerBase实现了一些基础的策略,而AudioPolicyManagerDefault则是终究的实现类。除了AudioPolicyService,面后这两个类也是我们研究Audio Policy的重点

        Step 4@ AudioPolicyService::AudioPolicyService. 行进初始化检测,原生态的实现直接返回0

        Step 5@ AudioPolicyService::AudioPolicyService. 判断是否强制执行相机照拍声音

        Step 6@ AudioPolicyService::AudioPolicyService. 加载音频效果文件(如果存在的话),文件路径如下:

        

     AUDIO_EFFECT_DEFAULT_CONFIG_FILE"/system/etc/audio_effects.conf"

     AUDIO_EFFECT_VENDOR_CONFIG_FILE"/vendor/etc/audio_effects.conf"

     这样AudioPolicyService就实现了构造,它在ServiceManager中的注册名称为"media.audio_policy"。其中包含的mpAudioPolicy变量是实际的策略制订者,而它也是由HAL层创建的,换句话说是根据件硬厂商自己的“意愿”来执行策略的。

        

    1.1.3 AudioPolicyService加载音频设备

        在AudioFlinger的“设备管理”节小,我们曾简单提及AudioPolicyService将通过解析配置文件来加载以后统系中的音频设备。体具而言,当AudioPolicyService构造时创建了一个Audio PolicyDevice(mpAudioPolicyDev)并由此打开一个AudioPolicy(mpAudioPolicy)——这个Policy默许情况下的实现是legacy_audio_policy::policy(数据型类audio_policy)。同时legacy_audio_policy还包含了一个AudioPolicyInterface成员变量,它会被初始化为一个AudioPolicyManagerDefault,这些都是我们在前一个节小析分过的。

        那么AudioPolicyService在什么时候去加载音频设备呢?

        除了后期的动态添加外,另外一个重要途径是通过AudioPolicyManagerDefault的父类,即AudioPolicyManagerBase的构造函数。

        

    AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface*clientInterface)…

    {   mpClientInterface= clientInterface;

        …

        if (loadAudioPolicyConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE) != NO_ERROR){

            if (loadAudioPolicyConfig(AUDIO_POLICY_CONFIG_FILE) != NO_ERROR) {

                defaultAudioPolicyConfig();

            }

        }

        for (size_t i = 0; i < mHwModules.size();i++) {

           mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->mName);

            if(mHwModules[i]->mHandle == 0) {

                continue;

            }

            for (size_t j = 0; j< mHwModules[i]->mOutputProfiles.size(); j++)

            {

                const IOProfile*outProfile = mHwModules[i]->mOutputProfiles[j];

                if(outProfile->mSupportedDevices & mAttachedOutputDevices) {

                    AudioOutputDescriptor*outputDesc = new AudioOutputDescriptor(outProfile);

                   outputDesc->mDevice = (audio_devices_t)(mDefaultOutputDevice &

                                                               outProfile->mSupportedDevices);

                    audio_io_handle_t output =mpClientInterface->openOutput(…);

                                    …              

    }

        不同的Android产品在音频的设计上常通是有差异的,利用配置文件的形式(audio_policy.conf)可以使厂商方便地描述其产品中所包含的音频设备,这个文件的存放路径有两处:

        

    #define AUDIO_POLICY_VENDOR_CONFIG_FILE  "/vendor/etc/audio_policy.conf"

    #define AUDIO_POLICY_CONFIG_FILE"/system/etc/audio_policy.conf"

        如果audio_policy.conf不存在的话,则统系将使用默许的配置,体具实现在defaultAudioPolicyConfig中。通过配置文件可以读取如下信息:

        ·        有哪些audiointerface,比如有没有“primary”、“a2dp”、“usb”

        ·        个每audiointerface的属性。比如持支的sampling_rates、formats、持支哪些device等等。这些属性是在loadOutput@AudioPolicyManagerBase中读取的,并存储到HwModule->mOutputProfiles中。个一每audiointerface下可能有多少个output和input,而个每output/input下又有多少体具的持支属性,系关如下图所示:

        

     

        

        图 13‑19 audio_policy.conf中各素元系关图

        大家可以自己打开一个audio_policy.conf来体具解了这个文件的格式求要,我们这里就不做深入讲解了。

        读取了相关配置后,接下来就要打开这些设备了。AudioPolicyService只是策略制订者,而非执行者,那么是由谁来实现这些体具的工作呢?没错,定一是AudioFlinger。我们可以看到上述函数段中有一个mpClientInterface变量,它是否和AudioFlinger有联系?可以先来析分下这个变量是如何来的。

        很明显的mpClientInterface这个变量在AudioPolicyManagerBase构造函数的第一行行进了初始化,再回溯追踪,可以发现它的根源在AudioPolicyService的构造函数中,对应的代码语句如下:

        

    rc =mpAudioPolicyDev->create_audio_policy(mpAudioPolicyDev, &aps_ops, this, &mpAudioPolicy);                           

        在这个场景下,函数create_audio_policy对应的是create_legacy_ap,并将传入的aps_ops组装到一个AudioPolicyCompatClient对象中,也就是mpClientInterface所指向的那个对象。

        换句话说,mpClientInterface->loadHwModule实际上调用的就是aps_ops->loadHwModule,即:

        

    static audio_module_handle_t  aps_load_hw_module(void*service,const char *name)

    {

        sp<IAudioFlinger> af= AudioSystem::get_audio_flinger();

        …

        returnaf->loadHwModule(name);

    }

        AudioFlinger终于出现了,同样的情况也适用于mpClientInterface->openOutput,代码如下:

        

    static audio_io_handle_t  aps_open_output(…)

    {

        sp<IAudioFlinger> af= AudioSystem::get_audio_flinger();

        …

        return  af->openOutput((audio_module_handle_t)0,pDevices, pSamplingRate, pFormat, pChannelMask,

                             pLatencyMs, flags);

    }

        再回到AudioPolicyManagerBase的构造函数中来,for循环的目标有两个:

        Ø  利用loadHwModule来加载从audio_policy.conf中解析出的audio interface,即mHwModules数组中的素元

        Ø  利用openOutput来打开各audio interface中包含的所有Output

        关于AudioFlinger中这两个函数的实现,我们在前一个节小已经析分过了,这里终于把它们串起来了。通过AudioPolicyManagerBase,AudioPolicyService解析出了设置中的音频配置,并利用AudioFlinger供给的口接实现了全部音频统系的部署,从而为面后层上应用使用音频设备供给了底层支撑。下一节小我们就看下层上应用体具是如何使用这一框架来播放音频的。

    文章结束给大家分享下程序员的一些笑话语录: 祝大家在以后的日子里. 男生象Oracle般健壮; 女生象win7般漂亮; 桃花运象IE中毒般频繁; 钱包如Gmail容量般壮大, 升职速度赶上微软打补丁 , 追女朋友像木马一样猖獗, 生活像重装电脑后一样幸福, 写程序敲代码和聊天一样有**。

  • 相关阅读:
    使用yum命令报错
    CentOS6.8安装Python3.6.3
    解决 linux 下安装 node 报: command not found
    Python的pip源切换为国内阿里云镜像
    开源Java加密工具Jasypt 1.4发布
    JavaFX对Java开发者到底意味着什么?
    16 个印象深刻的 HTML5/CSS3/JavaScript 体验
    高效的Java异常处理
    Java开发的学习过历程
    Java中23种设计模式详解
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3022837.html
Copyright © 2011-2022 走看看