Android開發之音訊配置檔案audio_policy.conf解析全過程

有頭髮的猿發表於2018-09-15

本文基於android7.0分析

一、概念

audio_policy.conf: 顧名思義 audio hw 模組配置檔案,用於載入音訊硬體抽象層動態庫。得到系統所支援的輸入、輸出音訊裝置。位於系統 /system/etc/

二、系統解析

以如下audio_policy.conf為例:

# 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 "\n".

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
      }
    }
  }
}



第一小節已經說了 audio_policy.conf 檔案 是 用於載入音訊硬體抽象層動態庫,而系統音訊是否能夠輸入輸出則取決於這些動態庫是否能夠載入成功。而是否能夠載入自定義的音訊庫,則取決你是否在配置檔案中加入自定義的音訊庫配置資訊。

android 許多核心模組在開機的時候就要伴隨系統的主程式啟動而啟動,音訊服務當然也不例外,而載入音訊hw模組動態庫隸屬於音訊服務中,並且是在初始化的過程中,因為這樣才能保證一開機系統音訊便能夠正常使用。

通過 ps -le 命令可以看到系統中第一個程式為init
這裡寫圖片描述

init 程式有個任務是啟動init.rc,

init.rc 會啟動 audioserver.rc,

audioserver.rc 位於 frameworks\av\media\audioserver
audioserver.rc 會啟動 音訊服務的主入口:main_audioserver.cpp

main_audioserver.cpp 位於 frameworks\av\media\audioserver
main_audioserver.cpp 主入口main函式會初始化 AudioPolicyService物件

AudioPolicyService.cpponFirstRef() 函式初始化 中 呼叫

extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)

AudioPolicyService.cpp位於\frameworks\av\services\audiopolicy\service

createAudioPolicyManager 初始化 AudioPolicyManager物件
AudioPolicyManager.cpp 位於\frameworks\av\services\audiopolicy\managerdefault

AudioPolicyManager.cpp 建構函式 涉及最終解析 audio_policy.conf

好的,到了這裡終於到了解析部分了,其實上面的流程也是音訊模組的啟動大致過程。有興趣的可以去看原始碼深入瞭解完整的啟動過程。

讓我們找到AudioPolicyManager.cpp 建構函式如下部分

AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices,mDefaultOutputDevice, speakerDrcEnabled);
if ((ConfigParsingUtils::loadConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE, config) != NO_ERROR) &&
            (ConfigParsingUtils::loadConfig(AUDIO_POLICY_CONFIG_FILE, config) != NO_ERROR))

首先看到了 AudioPolicyConfig物件
AudioPolicyConfig.h 原始碼位於:
\frameworks\av\services\audiopolicy\common\managerdefinitions\include

隨後看到 ConfigParsingUtils物件 呼叫靜態的函式 loadConfig
ConfigParsingUtils.cpp
位於 \frameworks\av\services\audiopolicy\common\managerdefinitions\src

loadConfig 函式需要兩個引數
const char *path //配置檔案的路徑 即/system/etc/
AudioPolicyConfig &config
原始碼如下:

/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <AudioGain.h>
#include <VolumeCurve.h>
#include <AudioPort.h>
#include <AudioPatch.h>
#include <DeviceDescriptor.h>
#include <IOProfile.h>
#include <HwModule.h>
#include <AudioInputDescriptor.h>
#include <AudioOutputDescriptor.h>
#include <AudioPolicyMix.h>
#include <EffectDescriptor.h>
#include <SoundTriggerSession.h>
#include <SessionRoute.h>

namespace android {

class AudioPolicyConfig
{
public:
    AudioPolicyConfig(HwModuleCollection &hwModules,
                      DeviceVector &availableOutputDevices,
                      DeviceVector &availableInputDevices,
                      sp<DeviceDescriptor> &defaultOutputDevices,
                      bool &isSpeakerDrcEnabled,
                      VolumeCurvesCollection *volumes = nullptr)
        : mHwModules(hwModules),
          mAvailableOutputDevices(availableOutputDevices),
          mAvailableInputDevices(availableInputDevices),
          mDefaultOutputDevices(defaultOutputDevices),
          mVolumeCurves(volumes),
          mIsSpeakerDrcEnabled(isSpeakerDrcEnabled)
    {}

    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);
    }

    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("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->mOutputProfiles.add(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->mInputProfiles.add(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;
    bool &mIsSpeakerDrcEnabled;
};

}; // namespace android

可以看出 AudioPolicyConfig物件 為封裝的audio_policy.conf 的物件。
AudioPolicyConfig物件 包含了audio_policy.conf 中所有hw音訊模組的集合、可獲取的輸入、輸出裝置的集合,預設輸出裝置的集合

分析完 AudioPolicyConfig物件 ,來到 loadConfig

//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\n", path);

    return NO_ERROR;
}

前面 load_fileconfig_nodeconfig_load 三個函式用於載入 audio_policy.conf檔案 並將檔案中所有資料以 cnode 結構體的形式 儲存在 變數root 中

audio_policy.conf檔案分為兩大塊:

modules 模組
GlobalConfig 全域性配置

cnode定義在 config_utils.h
位於 \system\core\include\cutils
如下:

typedef struct cnode cnode;


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

讓我們來理解下 cnode ,有助於我們後續分析,
其中 ***{} 前面加node name 和兩個大括號{}一個組合代表cnode
以上面的audio_policy.conf為例:

# 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 "\n".

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_childprimary{}
那麼audio_hw_modules{}nextusb{}
那麼audio_hw_modules{}last_childa2dp{}
那麼audio_hw_modules{}value=""
那麼audio_hw_modules{}name="audio_hw_modules"
…以此類推

瞭解了cnode 之後,
我們首先看到audio_policy.conf的第一個大模組,modules模組,看到 loadHwModules 函式

/**
audio_hw_modules{}
*/
//static
void ConfigParsingUtils::loadHwModules(cnode *root, HwModuleCollection &hwModules,
                                       AudioPolicyConfig &config)
{
    cnode *node = config_find(root, AUDIO_HW_MODULE_TAG);
    if (node == NULL) {
        return;
    }
   /**
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.c

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 */
    for(node = root->first_child; node; node = node->next)
        if(!strcmp(node->name, name))
            match = node;

    return match;
}

遍歷一個大cnode ,通過name 與cnode->name匹配,找到相等的子cnode,並返回。

我們這裡通過 巨集定義 ,原始碼位於:
\frameworks\av\services\audiopolicy\common\managerdefinitions\include\audio_policy_conf.h

// hw modules descriptions
#define AUDIO_HW_MODULE_TAG "audio_hw_modules"

找到 audio_hw_modules{} 模組,
隨之遍歷audio_hw_modules{} 模組,之後為每個音訊hw 動態庫建立了 HwModule物件

例如:audio_hw_modules{}->first_child=primary{}
建立了 HwModule物件 並將 primary{}->name 傳入構造,作為HwModule物件name 欄位
HwModule物件 位於:
\frameworks\av\services\audiopolicy\common\managerdefinitions\include\HwModule

然後使用 HwModuleCollection 物件 容器增加每個 HwModule物件
找到 HwModuleCollection 物件原始碼,位於:
\frameworks\av\services\audiopolicy\common\managerdefinitions\include\HwModule

class HwModuleCollection : public Vector<sp<HwModule> >
{
public:
    sp<HwModule> getModuleFromName(const char *name) const;

    sp<HwModule> getModuleForDevice(audio_devices_t device) const;

    sp<DeviceDescriptor> getDeviceDescriptor(const audio_devices_t device,
                                             const char *device_address,
                                             const char *device_name,
                                             bool matchAdress = true) const;

    status_t dump(int fd) const;
};

可以看到 HwModuleCollection 物件 為泛型為 HwModule 物件 的集合

接著解析每個音訊hw模組,首先來到 primary{} ,看到 loadHwModule

/**
primary {}
*/

//static
status_t ConfigParsingUtils::loadHwModule(cnode *root, sp<HwModule> &module,
                                          AudioPolicyConfig &config)
{
    status_t status = NAME_NOT_FOUND;
	/**
           devices{}
	     devices{}
	*/
    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);
    }

	/**
	outputs {}
	*/
    node = config_find(root, OUTPUTS_TAG);
    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{}
			spdif_device_raw{}
		
		*/
            node = node->next;
        }
    }

	/**
	inputs{}
	inputs{}
	*/
    node = config_find(root, INPUTS_TAG);
    if (node != NULL) {
        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 ---->稱為模組輸出裝置解析
OUTPUTS_TAG ---->稱為模組輸入裝置解析
loadModuleGlobalConfig ---->稱為模組全域性配置解析

首先看到 DEVICES_TAG,也就是 primary{.....devices{}...}

看到程式碼中又是通過一個while迴圈遍歷primary{.....devices{}...}

然後通過 loadHwModuleDevice 函式解析 primary{.....devices{}...} 子cnode,

HwModule物件 包含 DeviceVector 物件 屬性

DeviceVector 物件 找到原始碼,位於:
\frameworks\av\services\audiopolicy\common\managerdefinitions\src\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, 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, 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

/**
 speaker{}
  HDMI {}
*/
//static
status_t ConfigParsingUtils::loadHwModuleDevice(cnode *root, DeviceVector &devices)
{
    /**
        type{}
        type{}
	*/
    cnode *node = root->first_child;

    audio_devices_t type = AUDIO_DEVICE_NONE;
    while (node) {
        if (strcmp(node->name, APM_DEVICE_TYPE) == 0) {
            DeviceConverter::fromString(node->value, type);
        break;
        }
        node = node->next;
    }
    if (type == AUDIO_DEVICE_NONE ||
            (!audio_is_input_device(type) && !audio_is_output_device(type))) {
        ALOGW("loadDevice() bad type %08x", type);
        return BAD_VALUE;
    }
    sp<DeviceDescriptor> deviceDesc = new DeviceDescriptor(type, String8(root->name));

     /**
        type{}
        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);
        }
	/**
	 gains {}

	*/
        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;
}

通過 loadHwModuleDevice 也看出 使用 DeviceDescriptor 物件描述primary{.....devices{}...} 子cnode,
DeviceDescriptor 物件原始碼位於:
\frameworks\av\services\audiopolicy\common\managerdefinitions\include\DeviceDescriptor.h

class DeviceDescriptor : public AudioPort, public AudioPortConfig
{
....
};

DeviceDescriptor物件 繼承自 AudioPort 物件AudioPortConfig物件

DeviceDescriptor 物件 構造需要name和type屬性,原始碼位於:
\frameworks\av\services\audiopolicy\common\managerdefinitions\src\DeviceDescriptor.cpp

...
namespace android {

DeviceDescriptor::DeviceDescriptor(audio_devices_t type, const String8 &tagName) :
    AudioPort(String8(""), AUDIO_PORT_TYPE_DEVICE,
              audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK :
                                             AUDIO_PORT_ROLE_SOURCE),
    mAddress(""), mTagName(tagName), mDeviceType(type), mId(0)
{
    if (type == AUDIO_DEVICE_IN_REMOTE_SUBMIX || type == AUDIO_DEVICE_OUT_REMOTE_SUBMIX ) {
        mAddress = String8("0");
    }
}
...

根據type給AudioPort物件 的第三個引數 role 賦值,如果是output的type,則 role=AUDIO_PORT_ROLE_SINK ,input role=AUDIO_PORT_ROLE_SOURCE
AudioPort物件 原始碼位於:
\frameworks\av\services\audiopolicy\common\managerdefinitions\src\AudioPort.h

...
class AudioPort : public virtual RefBase
{
public:
    AudioPort(const String8& name, audio_port_type_t type,  audio_port_role_t role) :
        mName(name), mType(type), mRole(role), mFlags(AUDIO_OUTPUT_FLAG_NONE) {}
 ...      
 }

可以看出 primary{.....devices{}...} 子cnode 中可以包含
type ,gains,channel_masks,address屬性

channel_masks屬性 又封裝在AudioProfile物件
AudioProfile物件 原始碼位於:
\frameworks\av\services\audiopolicy\common\managerdefinitions\include\AudioProfile.h
AudioProfile物件 構造需要 取樣位寬、聲道,取樣率容器,三個引數。
聲道引數則為 channel_masks 屬性的值

gains通過 loadDeviceDescriptorGains函式 再到 loadAudioPortGains函式

/**
gains {}

*/
void ConfigParsingUtils::loadAudioPortGains(cnode *root, AudioPort &audioPort)
{
	/**
	gain_1 {}
	*/
    cnode *node = root->first_child;
    int index = 0;
    while (node) {
        ALOGV("loadGains() loading gain %s", node->name);
        loadAudioPortGain(node, audioPort, index++);
        node = node->next;
    }
}

可以看到 loadAudioPortGain函式 解析 gains {}
看到loadAudioPortGain函式

/**
gain_1 {}
*/
//static
void ConfigParsingUtils::loadAudioPortGain(cnode *root, AudioPort &audioPort, int index)
{
	/**
	mode{}
	*/
    cnode *node = root->first_child;

    sp<AudioGain> gain = new AudioGain(index, audioPort.useInputChannelMask());

    while (node) {
        if (strcmp(node->name, GAIN_MODE) == 0) {
            gain->setMode(GainModeConverter::maskFromString(node->value));
        } else if (strcmp(node->name, GAIN_CHANNELS) == 0) {
            audio_channel_mask_t mask;
            if (audioPort.useInputChannelMask()) {
                if (InputChannelConverter::fromString(node->value, mask)) {
                    gain->setChannelMask(mask);
                }
            } else {
                if (OutputChannelConverter::fromString(node->value, mask)) {
                    gain->setChannelMask(mask);
                }
            }
        } else if (strcmp(node->name, GAIN_MIN_VALUE) == 0) {
            gain->setMinValueInMb(atoi(node->value));
        } else if (strcmp(node->name, GAIN_MAX_VALUE) == 0) {
            gain->setMaxValueInMb(atoi(node->value));
        } else if (strcmp(node->name, GAIN_DEFAULT_VALUE) == 0) {
            gain->setDefaultValueInMb(atoi(node->value));
        } else if (strcmp(node->name, GAIN_STEP_VALUE) == 0) {
            gain->setStepValueInMb(atoi(node->value));
        } else if (strcmp(node->name, GAIN_MIN_RAMP_MS) == 0) {
            gain->setMinRampInMs(atoi(node->value));
        } else if (strcmp(node->name, GAIN_MAX_RAMP_MS) == 0) {
            gain->setMaxRampInMs(atoi(node->value));
        }
        node = node->next;
    }

    ALOGV("loadGain() adding new gain mode %08x channel mask %08x min mB %d max mB %d",
          gain->getMode(), gain->getChannelMask(), gain->getMinValueInMb(),
          gain->getMaxValueInMb());

    if (gain->getMode() == 0) {
        return;
    }
    audioPort.mGains.add(gain);
}

可以看出 通過 AudioGain物件 封裝 gains {} 子cnode
gains {} 子cnode可以包含如下屬性:
mode、channel_mask、min_value_mB、max_value_mB、default_value_mB、step_value_mB、min_ramp_ms、max_ramp_ms

最後將所有的 AudioGain物件 增加到 AudioGainCollection物件容器中,
AudioGainCollection物件隸屬於 AudioProfile物件
DeviceDescriptor物件 繼承自 AudioPort 物件

到這裡DEVICES_TAG也就結束了

總結一下:

primary { ---->HwModule ---->HwModuleCollection

#DeviceVector
devices {
speaker { ----->DeviceDescriptor ---->DeviceVector
type AUDIO_DEVICE_OUT_SPEAKER
gains {
gain_1 { —> AudioGain —>AudioGainCollection —>AudioPort
mode AUDIO_GAIN_MODE_JOINT
min_value_mB -8400
max_value_mB 4000
default_value_mB 0
step_value_mB 100
}
}
}
HDMI { ----->DeviceDescriptor ---->DeviceVector
type AUDIO_DEVICE_OUT_AUX_DIGITAL
}
SPDIF { ----->DeviceDescriptor ---->DeviceVector
type AUDIO_DEVICE_OUT_SPDIF
}
wired_headphone { ----->DeviceDescriptor ---->DeviceVector
type AUDIO_DEVICE_OUT_WIRED_HEADPHONE
}
wired_headset { ----->DeviceDescriptor ---->DeviceVector
type AUDIO_DEVICE_OUT_WIRED_HEADSET
}
BT_sco { ----->DeviceDescriptor ---->DeviceVector
type AUDIO_DEVICE_OUT_BLUETOOTH_SCO
}
BT_sco_headset { ----->DeviceDescriptor ---->DeviceVector
type AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET
}

}

接著回到loadHwModule,看看 OUTPUTS_TAG

/**
	outputs {}
	*/
    node = config_find(root, OUTPUTS_TAG);
    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{}
			spdif_device_raw{}
		
		*/
            node = node->next;
        }
    }

首先找到primary{.....outputs{}...}
然後通過 loadHwModuleProfile 函式解析 outputs{} 每個子cnode

根據示例,來到第一個字cnode primary{}

 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
      }

loadHwModuleProfile 函式如下:

/**
primary {}
primary{}
blemic{}
*/
//static
status_t ConfigParsingUtils::loadHwModuleProfile(cnode *root, sp<HwModule> &module,
                                                 audio_port_role_t role)
{
	/**	
	sampling_rates{}
	sampling_rates{}
	*/
    cnode *node = root->first_child;

    sp<IOProfile> profile = new IOProfile(String8(root->name), role);

    AudioProfileVector audioProfiles;
    SampleRateVector sampleRates;
    ChannelsVector channels;
    FormatVector formats;

    while (node) {
        if (strcmp(node->name, FORMATS_TAG) == 0 &&
                strcmp(node->value, DYNAMIC_VALUE_TAG) != 0) {
            formats = formatsFromString(node->value);
        } else if (strcmp(node->name, SAMPLING_RATES_TAG) == 0 &&
                  strcmp(node->value, DYNAMIC_VALUE_TAG) != 0) {
            collectionFromString<SampleRateTraits>(node->value, sampleRates);
        } else if (strcmp(node->name, CHANNELS_TAG) == 0 &&
                   strcmp(node->value, DYNAMIC_VALUE_TAG) != 0) {
            if (role == AUDIO_PORT_ROLE_SINK) {
                channels = inputChannelMasksFromString(node->value);
            } else {
                channels = outputChannelMasksFromString(node->value);
            }
        } else if (strcmp(node->name, DEVICES_TAG) == 0) {
            DeviceVector devices;
            loadDevicesFromTag(node->value, devices, module->getDeclaredDevices());
            profile->setSupportedDevices(devices);
        } else if (strcmp(node->name, FLAGS_TAG) == 0) {
            if (role == AUDIO_PORT_ROLE_SINK) {
                profile->setFlags(InputFlagConverter::maskFromString(node->value));
            } else {
                profile->setFlags(OutputFlagConverter::maskFromString(node->value));
            }
        } else if (strcmp(node->name, GAINS_TAG) == 0) {
            loadAudioPortGains(node, *profile);
        }
	/**
	channel_masks{}
	formats{}
	devices{}
	channel_masks{}
	formats{}
	devices{}
	*/
        node = node->next;
    }
    if (formats.isEmpty()) {
        sp<AudioProfile> profileToAdd = new AudioProfile(gDynamicFormat, channels, sampleRates);
        profileToAdd->setDynamicFormat(true);
        profileToAdd->setDynamicChannels(channels.isEmpty());
        profileToAdd->setDynamicRate(sampleRates.isEmpty());
        audioProfiles.add(profileToAdd);
    } else {
        for (size_t i = 0; i < formats.size(); i++) {
            // For compatibility reason, for each format, creates a profile with the same
            // collection of rate and channels.
            sp<AudioProfile> profileToAdd = new AudioProfile(formats[i], channels, sampleRates);
            profileToAdd->setDynamicFormat(formats[i] == gDynamicFormat);
            profileToAdd->setDynamicChannels(channels.isEmpty());
            profileToAdd->setDynamicRate(sampleRates.isEmpty());
            audioProfiles.add(profileToAdd);
        }
    }
    profile->setAudioProfiles(audioProfiles);
    ALOGW_IF(!profile->hasSupportedDevices(), "load%s() invalid supported devices",
             role == AUDIO_PORT_ROLE_SINK ? "Input" : "Output");
    if (profile->hasSupportedDevices()) {
        ALOGV("load%s() adding Supported Devices %04x, mFlags %04x",
              role == AUDIO_PORT_ROLE_SINK ? "Input" : "Output",
              profile->getSupportedDevicesType(), profile->getFlags());
        return module->addProfile(profile);
    }
    return BAD_VALUE;
}

從以上可以看到 outputs{} 子cnode通過 IOProfile物件 解析封裝,

outputs{} 子cnode可以定義以下屬性:
formats、sampling_rates、channel_masks、devices、 flags、gains

而formats —> 通過泛型為audio_format_tFormatVector容器封裝起來
sampling_rates–> 泛型為uint32_tSampleRateVector容器,
channel_masks --> 泛型為audio_channel_mask_tChannelsVector 容器

devices 屬性 的流是這樣:


//static
void ConfigParsingUtils::loadDevicesFromTag(const char *tag, DeviceVector &devices,
                                            const DeviceVector &declaredDevices)
{
    char *tagLiteral = strndup(tag, strlen(tag));
    char *devTag = strtok(tagLiteral, "|");
    while (devTag != NULL) {
        if (strlen(devTag) != 0) {
            audio_devices_t type;
            if (DeviceConverter::fromString(devTag, type)) {
                uint32_t inBit = type & AUDIO_DEVICE_BIT_IN;
                type &= ~AUDIO_DEVICE_BIT_IN;
                while (type) {
                  audio_devices_t singleType =
                        inBit | (1 << (31 - __builtin_clz(type)));
                    type &= ~singleType;
                    sp<DeviceDescriptor> dev = new DeviceDescriptor(singleType);
                    devices.add(dev);
                }
            } else {
                sp<DeviceDescriptor> deviceDesc =
                        declaredDevices.getDeviceFromTagName(String8(devTag));
                if (deviceDesc != 0) {
                    devices.add(deviceDesc);
                }
            }
        }
        devTag = strtok(NULL, "|");
    }
    free(tagLiteral);
}

首先獲取到其屬性值,通過 “|” 將每個值拆分開來,

然後 判斷每個的值是否是device_type還是tagName,通過函式
DeviceConverter::fromString(devTag, type) 區分

如果是tagName則從之前第一部分解析DEVICES_TAG的devices{} 部分獲取到的DeviceVector 遍歷其,獲取DeviceDescriptor物件,如果為null,則不新增,如果不為null,則新增到outputs{}DeviceVector物件

如果是device_type則new DeviceDescriptor 將device_type 傳入作為其type值,而預設的 預設引數 “” 作為tagName。

而 gains 的流程跟DEVICES_TAG的devices{} 相同

接著 又將 FormatVector 、SampleRateVector、ChannelsVector 三個容器封裝在 AudioProfile物件 中,如果 FormatVector 為空,則只有一個 AudioProfile物件 ,否則,根據FormatVector.size() 決定AudioProfile物件的個數,通過AudioProfileVector物件 容器增加AudioProfile物件
AudioProfile物件位於:
\frameworks\av\services\audiopolicy\common\managerdefinitions\include\AudioProfile.h

看到 IOProfile 物件,原始碼位於:
\frameworks\av\services\audiopolicy\common\managerdefinitions\include\IOProfile.h

...
class IOProfile : public AudioPort
...

可以看到 IOProfile物件DeviceDescriptor物件一樣都繼承自AudioPort物件

到這裡 outputs{}的第一個子cnode primary {} 就解析完畢,示例中outputs{}其他子cnode hdmi_output {}spdif_device_raw{} 也是類似,不再累贅

到這裡OUTPUTS_TAG模組就解析完畢,
總結一下:

primary { ---->HwModule ---->HwModuleCollection

outputs {
#IOProfile
primary { —> IOProfile —>OutputProfileCollection & AudioPortVector
sampling_rates 48000 —>SampleRateVector —>AudioProfile —>AudioProfileVector
channel_masks AUDIO_CHANNEL_OUT_STEREO —>ChannelsVector -->AudioProfile -->AudioProfileVector
formats AUDIO_FORMAT_PCM_16_BIT –>FormatVector -->AudioProfile -->AudioProfileVector
devices speaker|HDMI|SPDIF|wired_headphone|wired_headset|BT_sco|BT_sco_headset
---->DeviceDescriptor —>DeviceVector
flags AUDIO_OUTPUT_FLAG_PRIMARY
}

}

}

接下看到 模組 INPUTS_TAG

/**
	inputs{}
	inputs{}
	*/
    node = config_find(root, INPUTS_TAG);
    if (node != NULL) {
        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;
        }
    }

對比發現 INPUTS_TAG & OUTPUTS_TAG 都是通過loadHwModuleProfile函式解析,只是在 IOProfile物件 物件中表現的role是不一樣的,如果是 OUTPUTS_TAGIOProfile物件 的role是 AUDIO_PORT_ROLE_SOURCEINPUTS_TAG 則是 AUDIO_PORT_ROLE_SINK

那麼最後來看下模組全域性的配置解析:

/**
primary {}
*/
//static
void ConfigParsingUtils::loadModuleGlobalConfig(cnode *root, const sp<HwModule> &module,
                                                AudioPolicyConfig &config)
{
/**
global_configuration{}
*/
    cnode *node = config_find(root, GLOBAL_CONFIG_TAG);

    if (node == NULL) {
        return;
    }
    DeviceVector declaredDevices;
    if (module != NULL) {
        declaredDevices = module->getDeclaredDevices();
    }
/**
attached_output_devices{}
*/
    node = node->first_child;
    while (node) {
        if (strcmp(ATTACHED_OUTPUT_DEVICES_TAG, node->name) == 0) {
            DeviceVector availableOutputDevices;
            loadDevicesFromTag(node->value, availableOutputDevices, declaredDevices);
            ALOGV("loadGlobalConfig() Attached Output Devices %08x",
                  availableOutputDevices.types());
            config.addAvailableOutputDevices(availableOutputDevices);
        } else if (strcmp(DEFAULT_OUTPUT_DEVICE_TAG, node->name) == 0) {
            audio_devices_t device = AUDIO_DEVICE_NONE;
            DeviceConverter::fromString(node->value, device);
            if (device != AUDIO_DEVICE_NONE) {
                sp<DeviceDescriptor> defaultOutputDevice = new DeviceDescriptor(device);
                config.setDefaultOutputDevice(defaultOutputDevice);
                ALOGV("loadGlobalConfig() mDefaultOutputDevice %08x", defaultOutputDevice->type());
            } else {
                ALOGW("loadGlobalConfig() default device not specified");
            }
        } else if (strcmp(ATTACHED_INPUT_DEVICES_TAG, node->name) == 0) {
            DeviceVector availableInputDevices;
            loadDevicesFromTag(node->value, availableInputDevices, declaredDevices);
            ALOGV("loadGlobalConfig() Available InputDevices %08x", availableInputDevices.types());
            config.addAvailableInputDevices(availableInputDevices);
        } else if (strcmp(AUDIO_HAL_VERSION_TAG, node->name) == 0) {
            uint32_t major, minor;
            sscanf((char *)node->value, "%u.%u", &major, &minor);
            module->setHalVersion(HARDWARE_DEVICE_API_VERSION(major, minor));
            ALOGV("loadGlobalConfig() mHalVersion = %04x major %u minor %u",
                  module->getHalVersion(), major, minor);
        }
        node = node->next;
    }
}

首先找到 primary {}的子cnode global_configuration{}
global_configuration{}支援以下屬性:
attached_output_devices、default_output_device、attached_input_devices、audio_hal_version

其中 attached_output_devices & attached_output_devices 也是通過 loadDevicesFromTag函式解析,並將可獲取的輸入、輸出裝置集合新增到AudioPolicyConfig 物件

而default_output_device則是直接new DeviceDescriptor,並傳入其值作為type,其物件作為AudioPolicyConfig 物件 預設的輸出裝置

audio_hal_version則是將其主、次版本值、拼接在一起,並設定為其HwModule物件 模組的版本。

到這裡我們的模組全域性配置就解析完畢,

這樣意味著我們已經將其中之一模組已經完整解析完畢,其他的每個模組也是類似。就不在累贅。

最後在看到audio_policy.conf中的另一個大模組,全域性配置GlobalConfig模組,

}

/**
audio_hw_modules{}
*/
//static
void ConfigParsingUtils::loadGlobalConfig(cnode *root, AudioPolicyConfig &config,
                                          const sp<HwModule>& primaryModule)
{
	/**
global_configuration{}
	*/
    cnode *node = config_find(root, GLOBAL_CONFIG_TAG);

    if (node == NULL) {
        return;
    }
	/**
	attached_output_devices{}

	*/
    node = node->first_child;
    while (node) {
        if (strcmp(SPEAKER_DRC_ENABLED_TAG, node->name) == 0) {
            bool speakerDrcEnabled;
            if (utilities::convertTo<std::string, bool>(node->value, speakerDrcEnabled)) {
                ALOGV("loadGlobalConfig() mSpeakerDrcEnabled = %d", speakerDrcEnabled);
                config.setSpeakerDrcEnabled(speakerDrcEnabled);
            }
        }
        node = node->next;
    }
    loadModuleGlobalConfig(root, primaryModule, config);
}

從上面可以看出全域性配置GlobalConfig模組modules模組 中的模組全域性配置
多了一個屬性
SPEAKER_DRC_ENABLED_TAG --> speaker_drc_enabled
其他的解析過程和modules模組 中的模組全域性配置 都是通過 loadModuleGlobalConfig函式解析。

到這裡的話整個audio_policy.conf就解析完畢了,現在我們來總結下

...
global_configuration {  
  attached_output_devices AUDIO_DEVICE_OUT_SPEAKER
   #--->addAvailableOutputDevices --->AudioPolicyConfig
  default_output_device AUDIO_DEVICE_OUT_SPEAKER
   # --->setDefaultOutputDevice  --->AudioPolicyConfig
  attached_input_devices AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_REMOTE_SUBMIX|AUDIO_DEVICE_IN_DIA_REMOTE
   # --->addAvailableInputDevices --->AudioPolicyConfig
}
...
audio_hw_modules {  #  --->HwModuleCollection  --->AudioPolicyConfig.setHwModules(hwModules);
...
  primary {#--->HwModule.mName--->HwModule(primary)
  ...
    global_configuration {   
      attached_output_devices AUDIO_DEVICE_OUT_SPEAKER  
      #--->AudioPolicyConfig.addAvailableOutputDevices 
      default_output_device AUDIO_DEVICE_OUT_SPEAKER
     # --->AudioPolicyConfig.setDefaultOutputDevice
      attached_input_devices AUDIO_DEVICE_IN_BUILTIN_MIC
     # --->AudioPolicyConfig.addAvailableInputDevices
      audio_hal_version 3.0
      #--->setHalVersion --->HwModule.mHalVersion
    }
    devices {  
      speaker {  #--->DeviceDescriptor-->DeviceVector-->HwModule.mDeclaredDevices
        type AUDIO_DEVICE_OUT_SPEAKER  
        #-->DeviceDescriptor.mDeviceType
        gains { 
          gain_1 { 
#-->AudioGain——>AudioPort.mGains(AudioGainCollection)-->DeviceDescriptor
            mode AUDIO_GAIN_MODE_JOINT 
             #--->AudioGain.mode
            min_value_mB -8400
            #--->AudioGain.min_value
            max_value_mB 4000
            #--->AudioGain.max_value
            default_value_mB 0
            #--->AudioGain.default_value
            step_value_mB 100
            #--->AudioGain.step_value
          }
        }
      }
...
    }
    outputs { 
    #OutputProfile-->IOProfile.AudioPort.mRole=AUDIO_PORT_ROLE_SOURCE
    ...
      primary {  #OutputProfile-->IOProfile--->AudioPort.mName
        sampling_rates 48000
#SampleRateVector-->AudioProfile-->AudioProfileVector-->IOProfile-->AudioPort.mProfiles
        channel_masks AUDIO_CHANNEL_OUT_STEREO
#ChannelsVector-->AudioProfile-->AudioProfileVector-->IOProfile-->AudioPort.mProfiles	
        formats AUDIO_FORMAT_PCM_16_BIT
#FormatVector-->AudioProfile-->AudioProfileVector-->IOProfile-->AudioPort.mProfiles	
        devices speaker|HDMI|SPDIF|wired_headphone|wired_headset|BT_sco|BT_sco_headset
#IOProfile.mSupportedDevices
        flags AUDIO_OUTPUT_FLAG_PRIMARY
#IOProfile.mFlags
      }
...
    }
    inputs { #InputProfile-->IOProfile.AudioPort.mRole=AUDIO_PORT_ROLE_SINK
      primary { #InputProfile-->IOProfile--->AudioPort.mName
        sampling_rates 8000|11025|12000|16000|22050|24000|32000|44100|48000
#SampleRateVector-->AudioProfile-->AudioProfileVector-->IOProfile-->AudioPort.mProfiles
        channel_masks AUDIO_CHANNEL_IN_MONO|AUDIO_CHANNEL_IN_STEREO
#ChannelsVector-->AudioProfile-->AudioProfileVector-->IOProfile-->AudioPort.mProfiles	
        formats AUDIO_FORMAT_PCM_16_BIT
#FormatVector-->AudioProfile-->AudioProfileVector-->IOProfile-->AudioPort.mProfiles	   
        devices AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET|AUDIO_DEVICE_IN_WIRED_HEADSET
#IOProfile.mSupportedDevices
      }
    }
    ...
  }
  ...
}

相關文章