• audio_policy.conf文件解析


    概述

    对于Android7.0之后,虽然不再使用audio_policy.conf文件,但是从学习的角度有必要去分析一下这个文件。

    1. AudioPolicyConfig config

    AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices, 
    mDefaultOutputDevice, speakerDrcEnabled);

    定义了一个AudioPolicyConfig的构造函数,源码如下:

    /frameworks/av/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h

    class AudioPolicyConfig
    {
    public:
       AudioPolicyConfig(HwModuleCollection &hwModules,
                         DeviceVector &availableOutputDevices,
                         DeviceVector &availableInputDevices,
                         sp<DeviceDescriptor> &defaultOutputDevices,
                         VolumeCurvesCollection *volumes = nullptr)
           : mHwModules(hwModules),
             mAvailableOutputDevices(availableOutputDevices),
             mAvailableInputDevices(availableInputDevices),
             mDefaultOutputDevices(defaultOutputDevices),
             mVolumeCurves(volumes),
             mIsSpeakerDrcEnabled(false)
       {}
    
       void setVolumes(const VolumeCurvesCollection &volumes)
       {
           if (mVolumeCurves != nullptr) {
               *mVolumeCurves = volumes;
           }
       }
    
       void setHwModules(const HwModuleCollection &hwModules)
       {
           mHwModules = hwModules;
       }
    
       void addAvailableDevice(const sp<DeviceDescriptor> &availableDevice)
       {
           if (audio_is_output_device(availableDevice->type())) {
               mAvailableOutputDevices.add(availableDevice);
           } else if (audio_is_input_device(availableDevice->type())) {
               mAvailableInputDevices.add(availableDevice);
           }
       }
    
       void addAvailableInputDevices(const DeviceVector &availableInputDevices)
       {
           mAvailableInputDevices.add(availableInputDevices);
       }
    
       void addAvailableOutputDevices(const DeviceVector &availableOutputDevices)
       {
           mAvailableOutputDevices.add(availableOutputDevices);
       }
    
       bool isSpeakerDrcEnabled() const { return mIsSpeakerDrcEnabled; }
    
       void setSpeakerDrcEnabled(bool isSpeakerDrcEnabled)
       {
           mIsSpeakerDrcEnabled = isSpeakerDrcEnabled;
       }
    
       const HwModuleCollection getHwModules() const { return mHwModules; }
    
       const DeviceVector &getAvailableInputDevices() const
       {
           return mAvailableInputDevices;
       }
    
       const DeviceVector &getAvailableOutputDevices() const
       {
           return mAvailableOutputDevices;
       }
    
        void setDefaultOutputDevice(const sp<DeviceDescriptor> &defaultDevice)
        {
            mDefaultOutputDevices = defaultDevice;
        }
    
        const sp<DeviceDescriptor> &getDefaultOutputDevice() const { return mDefaultOutputDevices; }
    
        void setDefault(void)
        {
            mDefaultOutputDevices = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPEAKER);
            sp<HwModule> module;
            sp<DeviceDescriptor> defaultInputDevice = new DeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC);
            mAvailableOutputDevices.add(mDefaultOutputDevices);
            mAvailableInputDevices.add(defaultInputDevice);
    
            module = new HwModule(AUDIO_HARDWARE_MODULE_ID_PRIMARY);
    
            sp<OutputProfile> outProfile;
            outProfile = new OutputProfile(String8("primary"));
            outProfile->attach(module);
            outProfile->addAudioProfile(
                    new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 44100));
            outProfile->addSupportedDevice(mDefaultOutputDevices);
            outProfile->setFlags(AUDIO_OUTPUT_FLAG_PRIMARY);
            module->addOutputProfile(outProfile);
    
            sp<InputProfile> inProfile;
            inProfile = new InputProfile(String8("primary"));
            inProfile->attach(module);
            inProfile->addAudioProfile(
                    new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO, 8000));
            inProfile->addSupportedDevice(defaultInputDevice);
            module->addInputProfile(inProfile);
    
            mHwModules.add(module);
        }
    
    private:
        HwModuleCollection &mHwModules; /**< Collection of Module, with Profiles, i.e. Mix Ports. */
        DeviceVector &mAvailableOutputDevices;
        DeviceVector &mAvailableInputDevices;
        sp<DeviceDescriptor> &mDefaultOutputDevices;
        VolumeCurvesCollection *mVolumeCurves;
        // TODO: remove when legacy conf file is removed. true on devices that use DRC on the
        // DEVICE_CATEGORY_SPEAKER path to boost soft sounds, used to adjust volume curves accordingly.
        // Note: remove also speaker_drc_enabled from global configuration of XML config file.
        bool mIsSpeakerDrcEnabled;
    };

    可以看出AudioPolicyConfig对象为封装的audio_policy.conf对象。
    AudioPolicyConfig对象包含了audio_policy.conf中所有hw音频模块的集合、可获取的输入、输出设备的集合、默认输出设备的集合

    2. ConfigParsingUtils::loadConfig

    调用ConfigParsingUtils类的静态成员函数loadConfig

    /frameworks/av/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp

    //static
    status_t ConfigParsingUtils::loadConfig(const char *path, AudioPolicyConfig &config)
    {
        cnode *root;
        char *data;
    
        data = (char *)load_file(path, NULL);
        if (data == NULL) {
            return -ENODEV;
        }
        root = config_node("", "");
        config_load(root, data);
    
        HwModuleCollection hwModules;
        loadHwModules(root, hwModules, config);
    
        // legacy audio_policy.conf files have one global_configuration section, attached to primary.
        loadGlobalConfig(root, config, hwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY));
    
        config.setHwModules(hwModules);
    
        config_free(root);
        free(root);
        free(data);
    
        ALOGI("loadAudioPolicyConfig() loaded %s
    ", path);
    
        return NO_ERROR;
    }

    前面load_file与config_node与config_load三个函数用于加载audio_policy.conf文件,并将文件中所有数据以cnode结构体的形式保存在变量root中。

    举个例子:

    从上面这个例子中可以看出:

    audio_policy.conf文件分为两大块:
    modules模块
    GlobalConfig全局配置

    我们来看一下cnode结构体的定义:

    /system/core/include/cutils/config_utils.h

    typedef struct cnode cnode;
    
    
    struct cnode
    {
        cnode *next;
        cnode *first_child;
        cnode *last_child;
        const char *name;
        const char *value;
    };

    以audio_policy.conf文件为例,再进一步理解cnode结构体。

    # Global configuration section:
    # - before audio HAL version 3.0:
    #   lists input and output devices always present on the device
    # as well as the output device selected by default.
    # Devices are designated by a string that corresponds to the enum in audio.h
    #
    global_configuration {
      attached_output_devices AUDIO_DEVICE_OUT_SPEAKER
      default_output_device AUDIO_DEVICE_OUT_SPEAKER
      attached_input_devices AUDIO_DEVICE_IN_BUILTIN_MIC
    #AUDIO_DEVICE_IN_REMOTE_SUBMIX|AUDIO_DEVICE_IN_DIA_REMOTE
    }
    #
    # - after and including audio HAL 3.0 the global_configuration section is included in each
    #   hardware module section.
    #   it also includes the audio HAL version of this hw module:
    #  global_configuration {
    #    ...
    #     audio_hal_version <major.minor>  # audio HAL version in e.g. 3.0
    #  }
    #   other attributes (attached devices, default device) have to be included in the
    #   global_configuration section of each hardware module
    
    
    # audio hardware module section: contains descriptors for all audio hw modules present on the
    # device. Each hw module node is named after the corresponding hw module library base name.
    # For instance, "primary" corresponds to audio.primary.<device>.so.
    # The "primary" module is mandatory and must include at least one output with
    # AUDIO_OUTPUT_FLAG_PRIMARY flag.
    # Each module descriptor contains one or more output profile descriptors and zero or more
    # input profile descriptors. Each profile lists all the parameters supported by a given output
    # or input stream category.
    # The "channel_masks", "formats", "devices" and "flags" are specified using strings corresponding
    # to enums in audio.h and audio_policy.h. They are concatenated by use of "|" without space or "
    ".
    
    audio_hw_modules {
    #HwModule
      primary {
      global_configuration {
          attached_output_devices AUDIO_DEVICE_OUT_SPEAKER
          default_output_device AUDIO_DEVICE_OUT_SPEAKER
         #attached_input_devices AUDIO_DEVICE_IN_BUILTIN_MIC
          audio_hal_version 3.0
        }
         #DeviceVector
        devices {
          speaker {
             #DeviceDescriptor  ->   DeviceVector
            type AUDIO_DEVICE_OUT_SPEAKER
            #AudioGain   ->   audioPort.mGains
            gains {
              gain_1 {
                mode AUDIO_GAIN_MODE_JOINT
                min_value_mB -8400
                max_value_mB 4000
                default_value_mB 0
                step_value_mB 100
              }
            }
          }
          HDMI {
            type AUDIO_DEVICE_OUT_AUX_DIGITAL
          }
          SPDIF {
            type AUDIO_DEVICE_OUT_SPDIF
          }
          wired_headphone {
            type AUDIO_DEVICE_OUT_WIRED_HEADPHONE
          }
          wired_headset {
            type AUDIO_DEVICE_OUT_WIRED_HEADSET
          }
          BT_sco {
            type AUDIO_DEVICE_OUT_BLUETOOTH_SCO
          }
          BT_sco_headset {
            type AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET
          }
        }
        outputs {
          #IOProfile
          primary {
              #SampleRateVector  -->AudioProfile  -->AudioProfileVector
            sampling_rates 48000
            #ChannelsVector   -->AudioProfile  -->AudioProfileVector
            channel_masks AUDIO_CHANNEL_OUT_STEREO
            #FormatVector    -->AudioProfile   -->AudioProfileVector
            formats AUDIO_FORMAT_PCM_16_BIT
            #IOProfile
            devices speaker|HDMI|SPDIF|wired_headphone|wired_headset|BT_sco|BT_sco_headset
            #IOProfile
            flags AUDIO_OUTPUT_FLAG_PRIMARY
          }
          #here for HDMI audio dynamic profile from edid
          hdmi_output {
            sampling_rates dynamic
            channel_masks dynamic
            formats dynamic
            devices HDMI
            flags AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_HW_AV_SYNC
          }
          spdif_device_raw {
            sampling_rates 32000|44100|48000
            channel_masks AUDIO_CHANNEL_OUT_STEREO|AUDIO_CHANNEL_OUT_5POINT1
            formats AUDIO_FORMAT_DTS|AUDIO_FORMAT_AC3
            devices SPDIF
            flags   AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_HW_AV_SYNC|AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO
          }
        }
        inputs {
          primary {
            sampling_rates 8000|11025|12000|16000|22050|24000|32000|44100|48000
            channel_masks AUDIO_CHANNEL_IN_MONO|AUDIO_CHANNEL_IN_STEREO
            formats AUDIO_FORMAT_PCM_16_BIT
            devices AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET|AUDIO_DEVICE_IN_WIRED_HEADSET
          }
        }
      }
      
      usb {
        outputs {
          usb_accessory {
            sampling_rates 44100
            channel_masks AUDIO_CHANNEL_OUT_STEREO
            formats AUDIO_FORMAT_PCM_16_BIT
            devices AUDIO_DEVICE_OUT_USB_ACCESSORY
          }
          usb_device {
            sampling_rates 44100
            channel_masks AUDIO_CHANNEL_OUT_STEREO
            formats AUDIO_FORMAT_PCM_16_BIT
            devices AUDIO_DEVICE_OUT_USB_DEVICE
          }
        }
        inputs {
          usb_device {
            sampling_rates 8000|11025|16000|22050|32000|44100|48000
            channel_masks AUDIO_CHANNEL_IN_MONO
            formats AUDIO_FORMAT_PCM_16_BIT
            devices AUDIO_DEVICE_IN_USB_DEVICE
         }
       }
      }
      r_submix {
        outputs {
          submix {
            sampling_rates 48000
            channel_masks AUDIO_CHANNEL_OUT_STEREO
            formats AUDIO_FORMAT_PCM_16_BIT
            devices AUDIO_DEVICE_OUT_REMOTE_SUBMIX
          }
        }
        inputs {
          submix {
            sampling_rates 48000
            channel_masks AUDIO_CHANNEL_IN_STEREO
            formats AUDIO_FORMAT_PCM_16_BIT
            devices AUDIO_DEVICE_IN_REMOTE_SUBMIX
          }
        }
      }
     a2dp {
        outputs {
          a2dp {
            sampling_rates 44100
            channel_masks AUDIO_CHANNEL_OUT_STEREO
            formats AUDIO_FORMAT_PCM_16_BIT
            devices AUDIO_DEVICE_OUT_ALL_A2DP
          }
        }
      }
    }

    整个文件为一个cnode,称为root
    那么,root->first_child=audio_hw_modules{}
    那么,root->next=NULL
    那么,root->Last_child=NULL
    那么,root->name=""
    那么,root->value=""

    那么audio_hw_modules{}的first_child为primary{}
    那么audio_hw_modules{}的next为usb{}
    那么audio_hw_modules{}的last_child为a2dp{}
    那么audio_hw_modules{}的value=""
    那么audio_hw_modules{}的name="audio_hw_modules"
    ....依次类推

    3. Modules模块

    需要分析函数 loadHwModules(root, hwModules, config)

    /frameworks/av/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp

    void ConfigParsingUtils::loadHwModules(cnode *root, HwModuleCollection &hwModules,
                                           AudioPolicyConfig &config)
    {
        //hw modules descriptions
        //#define AUDIO_HW_MODULE_TAG "audio_hw_modules"
        
        /*audio_hw_modules{}*/
        cnode *node = config_find(root, AUDIO_HW_MODULE_TAG);
        
        /*primary{}*/
        node = node->first_child;
        while (node) {
            ALOGV("loadHwModules() loading module %s", node->name);
            sp<HwModule> module = new HwModule(node->name);
            if (loadHwModule(node, module, config) == NO_ERROR) {
                hwModules.add(module);
            }
            
            /*usb{}*/
            node = node->next;
        }
        
    }

    看一下config_find函数

    /system/core/libcutils/config_utils.cpp

    cnode* config_find(cnode *root, const char *name)
    {
        cnode *node, *match = NULL;
    
        /* we walk the whole list, as we need to return the last (newest) entry */
        //遍历root的child,找到与name相匹配的cnode
        for(node = root->first_child; node; node = node->next)
            if(!strcmp(node->name, name))
                match = node;
    
        return match;
    }

    通过config_find函数找到了audio_hw_modules{}模块

    随后会遍历audio_Hw_modules{}模块,为每个音频hw动态库创建了HwModule对象。

    例如:audio_Hw_modules{}->first_child = primary{},primary{}->name = primary。

    new HwModule(node->name)即new HwModule(primary),创建了一个module对象指针

    HwModule::HwModule(const char *name, uint32_t halVersionMajor, uint32_t halVersionMinor)
        : mName(String8(name)),
          mHandle(AUDIO_MODULE_HANDLE_NONE)
    {
        setHalVersion(halVersionMajor, halVersionMinor);
    }

    接下来分析 loadHwModule(node, module, config)

    /frameworks/av/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp

    //static
    status_t ConfigParsingUtils::loadHwModule(cnode *root, sp<HwModule> &module,
                                              AudioPolicyConfig &config)
    {
        status_t status = NAME_NOT_FOUND;
        //如果我们以primary{}模块来分析,此时root就是primary{}
        //#define DEVICES_TAG "devices",在primary{}模块下,寻找devices{}的cnode,并放回
        cnode *node = config_find(root, DEVICES_TAG);
        if (node != NULL) {
            
            //speaker{}
            node = node->first_child;
            DeviceVector devices;
            while (node) {
                ALOGV("loadHwModule() loading device %s", node->name);
                status_t tmpStatus = loadHwModuleDevice(node, devices);
                if (status == NAME_NOT_FOUND || status == NO_ERROR) {
                    status = tmpStatus;
                }
                
                //HDMI{}.....
                node = node->next;
            }
            module->setDeclaredDevices(devices);
        }
        
        //#define OUTPUTS_TAG "outputs"
        node = config_find(root, OUTPUTS_TAG);
        
        //outputs{}
        if (node != NULL) {
        
            //primary{}
            node = node->first_child;
            while (node) {
                ALOGV("loadHwModule() loading output %s", node->name);
                status_t tmpStatus = loadHwModuleProfile(node, module, AUDIO_PORT_ROLE_SOURCE);
                if (status == NAME_NOT_FOUND || status == NO_ERROR) {
                    status = tmpStatus;
                }
                
                //hdmi_output{} ...
               node = node->next;
           }
       }
       
       //#define INPUTS_TAG "inputs"
       node = config_find(root, INPUTS_TAG);
       
       //inputs{}
       if (node != NULL) {
       
           //primary{}
           node = node->first_child;
           while (node) {
               ALOGV("loadHwModule() loading input %s", node->name);
               status_t tmpStatus = loadHwModuleProfile(node, module, AUDIO_PORT_ROLE_SINK);
               if (status == NAME_NOT_FOUND || status == NO_ERROR) {
                   status = tmpStatus;
               }
                node = node->next;
            }
        }
        loadModuleGlobalConfig(root, module, config);
        return status;
    }

    通过loadHwModule函数可以看出,每个HwModule对象,即每个音频库模块大致又分为四个大类:

    DEVICES_TAG ----->称为模块设备解析
    OUTPUTS_TAG ----->称为模块输出设备解析
    INPUTS_TAG ------>称为模块输入设备解析
    loadModuleGlobalConfig ---->称为模块全局配置解析

    DeviceVector devices定义了一个DeviceVector类对象

    /frameworks/av/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h

    class DeviceVector : public SortedVector<sp<DeviceDescriptor> >
    {
    public:
        DeviceVector() : SortedVector(), mDeviceTypes(AUDIO_DEVICE_NONE) {}
    
        ssize_t add(const sp<DeviceDescriptor>& item);
        void add(const DeviceVector &devices);
        ssize_t remove(const sp<DeviceDescriptor>& item);
        ssize_t indexOf(const sp<DeviceDescriptor>& item) const;
    
        audio_devices_t types() const { return mDeviceTypes; }
    
        sp<DeviceDescriptor> getDevice(audio_devices_t type, const String8& address) const;
        DeviceVector getDevicesFromType(audio_devices_t types) const;
        sp<DeviceDescriptor> getDeviceFromId(audio_port_handle_t id) const;
        sp<DeviceDescriptor> getDeviceFromTagName(const String8 &tagName) const;
        DeviceVector getDevicesFromTypeAddr(audio_devices_t type, const String8& address) const;
    
        audio_devices_t getDevicesFromHwModule(audio_module_handle_t moduleHandle) const;
    
        status_t dump(int fd, const String8 &tag, int spaces = 0, bool verbose = true) const;
    
    private:
        void refreshTypes();
        audio_devices_t mDeviceTypes;
    };

    可以看出DeviceVector对象为一个泛型为DeviceDescriptor对象的集合,由此可以得知,用DeviceDescriptor对象来描述每个primary{...devices{}...}子cnode

    那么那么,接下来看看怎样将每个primary{...devices{}...}子cnode解析成DeviceDescriptor对象

    分析 loadHwModuleDevice(node, devices)

    node为speaker{}; devices为类 DeviceVector的对象

    /frameworks/av/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp

    //static
    status_t ConfigParsingUtils::loadHwModuleDevice(cnode *root, DeviceVector &devices)
    {
        //type{}
        cnode *node = root->first_child;
    
        audio_devices_t type = AUDIO_DEVICE_NONE;
        while (node) {
        
            //#define APM_DEVICE_TYPE "type"
            //node->name = type
            if (strcmp(node->name, APM_DEVICE_TYPE) == 0) {
            
                //将speaker{}-->type->value转换为audio_devices_t类型的type
                deviceFromString(node->value, type);
                break;
            }
            node = node->next;
        }
        ......
        //创建DeviceDescriptor对象指针,
        sp<DeviceDescriptor> deviceDesc = new DeviceDescriptor(type, String8(root->name));
    
        //type{}
        node = root->first_child;
        while (node) {
            if (strcmp(node->name, APM_DEVICE_ADDRESS) == 0) {
                deviceDesc->mAddress = String8((char *)node->value);
            } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
                if (audio_is_input_device(type)) {
                    deviceDesc->addAudioProfile(
                            new AudioProfile(gDynamicFormat,
                                             inputChannelMasksFromString(node->value),
                                             SampleRateVector()));
                } else {
                    deviceDesc->addAudioProfile(
                            new AudioProfile(gDynamicFormat,
                                             outputChannelMasksFromString(node->value),
                                             SampleRateVector()));
                }
            } else if (strcmp(node->name, GAINS_TAG) == 0) {
                loadDeviceDescriptorGains(node, deviceDesc);
            }
            node = node->next;
        }
    
        ALOGV("loadDevice() adding device tag (literal type) %s type %08x address %s",
              deviceDesc->getTagName().string(), type, deviceDesc->mAddress.string());
    
        devices.add(deviceDesc);
        return NO_ERROR;
    }

    看一下类 DeviceDescriptor的构造函数

    /frameworks/av/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp

  • 相关阅读:
    linux 命令行远程登录 后台运行命令的方法
    再议perl写多线程端口扫描器
    perl 函数参数传递与返回值(一)
    Linux 删除带有特殊字符的文件
    桌面云的四大协议解析
    RemoteBox 1.6 发布,VirtualBox 管理工具
    gsoap
    Open Compute Project
    基于 Arduino 开发板,这款插座是可编程且开源的
    minnowboard
  • 原文地址:https://www.cnblogs.com/-glb/p/14258712.html
Copyright © 2020-2023  润新知