Android開發之音訊配置檔案audio_policy.conf解析全過程
本文基於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.cpp
在 onFirstRef()
函式初始化 中 呼叫
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_file
與 config_node
與 config_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_child
為 primary{}
那麼audio_hw_modules{}
的next
為 usb{}
那麼audio_hw_modules{}
的last_child
為 a2dp{}
那麼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_t
的FormatVector
容器封裝起來
sampling_rates–> 泛型為uint32_t
的SampleRateVector
容器,
channel_masks --> 泛型為audio_channel_mask_t
的ChannelsVector
容器
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_TAG
, IOProfile物件
的role是 AUDIO_PORT_ROLE_SOURCE
, INPUTS_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
}
}
...
}
...
}
相關文章
- 【sharpedge 】.NET配置檔案解析過程詳解
- Java初學者:Jsp開發環境配置全過程JavaJS開發環境
- Android WebView 上傳檔案支援全解析AndroidWebView
- MapReduce 執行全過程解析
- DNS解析全過程及原理DNS
- JVM 深入學習:Java 解析 Class 檔案過程解析JVMJava
- Android視訊開發進階(part2-MP4檔案的解析)Android
- Android官方開發文件Training系列課程中文版:分享檔案之配置檔案共享AndroidAI
- Android程式碼混淆配置(Proguard檔案解析)Android
- android下解析.plist配置檔案的xml解析器AndroidXML
- MDK編譯過程及檔案型別全解編譯型別
- TDP for SQL安裝配置全過程SQL
- linux iSCSI target配置全過程Linux
- AVPlayer之音訊,視訊音訊
- web音訊流轉發之音視訊直播Web音訊
- Oracle-解析啟動的全過程Oracle
- Nginx配置檔案解析Nginx
- redis配置檔案解析Redis
- SpringBoot配置檔案讀取過程分析Spring Boot
- 專案開發過程管理(草稿)
- solaris 10 網路配置全過程(轉)
- Android啟動過程深入解析Android
- Android開發中Retrofit常見註解全解析Android
- 透過例項看VCL元件開發全過程(一) (轉)元件
- 透過例項看VCL元件開發全過程(二) (轉)元件
- 04.Eclipse下Ndk開發(以檔案拆分合併為例模擬一下開發過程,參考檔案加密的過程)Eclipse加密
- 安卓平臺Flutter啟動過程全解析安卓Flutter
- MTK6577+Android之音訊(audio)移植Android音訊
- 基於EJB3.0的留言板專案的開發全過程
- 微信公眾號支付開發全過程(Java 版)Java
- java解析yaml配置檔案JavaYAML
- DHCP常用配置檔案解析
- Nginx配置檔案示例解析Nginx
- android解析plist檔案Android
- android: AAC檔案解析Android
- pydev部署開發全解析dev
- iOS 開發之解析Json檔案iOSJSON
- 理解 Android 程式啟動之全過程Android