前言
此音频架构梳理笔记、主要是因工作上需要在 Android8.1 以上版本中,增加 snd-aloop 虚拟声卡做前期准备工作, 本篇文章提纲挈领的把音频框架主线梳理清晰,通过这篇文章能够清晰如下内容:
1>. 声卡服务框架是什么时间产生、如何引发?
2>. 声卡框架主要模块都是什么,他们基本功能如何分配? audioFlinger、audioService、audioPolicyMannager等
3>. audio_policy_configuration.xml 与 audio_policy.conf 文件,是如何配置管理Android音频系统? xml文件解析一般规则。
4>. 厂家 audio_hw_hal 驱动是如何被加载至系统的,由谁加载的、加载到哪里去了?
5>. 安卓 AUDIO-HAL 与 Linux snd-driver 是如何关联起来的,如果管理不同声卡?
希望您阅读此文章时,带着上述 5 点内容,能够快速全面的对安卓音频系统有框架认知。由于 android 声卡涉及内容较多, 本比较中未分析 soundTrigger 相关内容。 后面将分享 android 添加虚拟声卡系列笔记内容,敬请阅读讨论。
一、 AndroidRuntime.so 引发思考
android 系统 framework 代码起点, frameworks/base/core/jni/AndroidRuntime.cpp 文件, 此文件是android系统主线程代码,代码内容涉及系统很多模块,此程序主要是注册模块的JNI接口方法。 其中涉及到模块 native、sensorHal、media、audioflinger、displayflinger、camera、serialport、bindler等模块 从各模块名称上、可看出是 android 系统核心组件内容,由此可见 AndroidRuntime 是系统框架的入口。
二、 Android 音频框架
Android音频系统有两大服务:一是AudioFlinger,二是AudioPolicyService。AudioFlinger负责向下 访问AudioHardwareInterface, 实现音频PCM数据的混音/输入/输出,实现音量调节; AudioPolicyService负责音 频输入输出设备的连接状态,音频策略调度即音频设备(如本地CODEC、Bluetooth A2DP、Headset)的切换 策略(注意它只是负责策略,真正的切换操作是在AudioFlinger中的openOutput,毕竟 AudioFlinger负责操作底层音频硬件)。
//> 此处敲黑板了!!! 如我们所知,BluetoothA2DP与ALSA设备并不走同一套 接口,因此 Android 的设计者就把ALSA设备接口扔到A2DP接口里面管理了。 这又是如何管理呢?简单来说,就是根据上层传下来的参数 devices,判断 devices 是否是 DEVICE_OUT_BLUETOOTH_A2DP, 如果是则走A2DP接口,如果不是则走ALSA设备接口。 https://blog.csdn.net/tronteng/article/details/8212641
2.0> audioserver 本地服务
@ frameworks/av/media/mediaserver/main_mediaserver.cpp 此程序是 audio 程序入口函数,在 android 系统初始化时,初始化脚本 audioserver.rc 文件、启动 audioserver 服务; 所有媒体服务端线程都在此被启动, 线程名称: /system/bin/mediaserver 。
#define LOG_TAG "audioserver"
#include <fcntl.h>
#include <sys/prctl.h>
#include <sys/wait.h>
#include <cutils/properties.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <utils/Log.h>
#include "AudioFlinger.h"
#include "AudioPolicyService.h"
#include "MediaLogService.h"
#include "RadioService.h"
#include "SoundTriggerHwService.h"
using namespace android;
int main(int argc __unused, char **argv)
{
signal(SIGPIPE, SIG_IGN);
bool doLog = (bool) property_get_bool("ro.test_harness", 0);
pid_t childPid;
if (doLog && (childPid = fork()) != 0) {
strcpy(argv[0], "media.log");
sp<ProcessState> proc(ProcessState::self());
MediaLogService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
for (;;) {
siginfo_t info;
int ret = waitid(P_PID, childPid, &info, WEXITED | WSTOPPED | WCONTINUED);
if (ret == EINTR) {
continue;
}
if (ret < 0) {
break;
}
char buffer[32];
const char *code;
switch (info.si_code) {
case CLD_EXITED:
code = "CLD_EXITED";
break;
case CLD_KILLED:
code = "CLD_KILLED";
break;
case CLD_DUMPED:
code = "CLD_DUMPED";
break;
case CLD_STOPPED:
code = "CLD_STOPPED";
break;
case CLD_TRAPPED:
code = "CLD_TRAPPED";
break;
case CLD_CONTINUED:
code = "CLD_CONTINUED";
break;
default:
snprintf(buffer, sizeof(buffer), "unknown (%d)", info.si_code);
code = buffer;
break;
}
struct rusage usage;
getrusage(RUSAGE_CHILDREN, &usage);
ALOG(LOG_ERROR, "media.log", "pid %d status %d code %s user %ld.%03lds sys %ld.%03lds",
info.si_pid, info.si_status, code,
usage.ru_utime.tv_sec, usage.ru_utime.tv_usec / 1000,
usage.ru_stime.tv_sec, usage.ru_stime.tv_usec / 1000);
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("media.log"));
if (binder != 0) {
Vector<String16> args;
binder->dump(-1, args);
}
switch (info.si_code) {
case CLD_EXITED:
case CLD_KILLED:
case CLD_DUMPED: {
ALOG(LOG_INFO, "media.log", "exiting");
_exit(0);
}
default:
break;
}
}
} else {
if (doLog) {
prctl(PR_SET_PDEATHSIG, SIGKILL);
setpgid(0, 0);
}
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
ALOGI("ServiceManager: %p", sm.get());
AudioFlinger::instantiate();
AudioPolicyService::instantiate();
RadioService::instantiate();
SoundTriggerHwService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
}
此线程启动服务有:AudioFlinger\AudioPolicyService\RadioService\SoundTriggerHwService 服务; 其中 RadioService 是电话服务,不是本次讨论内容略过。
2.1> AudioPolicyService 本地服务的创建
@ framework/av/services/audiopolicy/service/AudioPolicyService.cpp 此 AudioPolicyService::instantiate(); 函数执行将调用下面函数执行。
void AudioPolicyService::onFirstRef()
{
{
Mutex::Autolock _l(mLock);
mTonePlaybackThread = new AudioCommandThread(String8("ApmTone"), this);
mAudioCommandThread = new AudioCommandThread(String8("ApmAudio"), this);
mOutputCommandThread = new AudioCommandThread(String8("ApmOutput"), this);
#ifdef USE_LEGACY_AUDIO_POLICY
ALOGI("AudioPolicyService CSTOR in legacy mode");
const struct hw_module_t *module;
int rc = hw_get_module(AUDIO_POLICY_HARDWARE_MODULE_ID, &module);
if (rc) {
return;
}
rc = audio_policy_dev_open(module, &mpAudioPolicyDev);
ALOGE_IF(rc, "couldn't open audio policy device (%s)", strerror(-rc));
if (rc) {
return;
}
rc = mpAudioPolicyDev->create_audio_policy(mpAudioPolicyDev, &aps_ops, this,
&mpAudioPolicy);
ALOGE_IF(rc, "couldn't create audio policy (%s)", strerror(-rc));
if (rc) {
return;
}
rc = mpAudioPolicy->init_check(mpAudioPolicy);
ALOGE_IF(rc, "couldn't init_check the audio policy (%s)", strerror(-rc));
if (rc) {
return;
}
ALOGI("Loaded audio policy from %s (%s)", module->name, module->id);
#else
ALOGI("AudioPolicyService CSTOR in new mode");
mAudioPolicyClient = new AudioPolicyClient(this);
mAudioPolicyManager = createAudioPolicyManager(mAudioPolicyClient);
#endif
}
sp<AudioPolicyEffects>audioPolicyEffects = new AudioPolicyEffects();
{
Mutex::Autolock _l(mLock);
mAudioPolicyEffects = audioPolicyEffects;
}
}
2.1.1 legacy 模式、创建策略与声卡
@ hardware/libhardware/include/hardware/audio_policy.h audio_policy 宏定义
#define AUDIO_POLICY_HARDWARE_MODULE_ID "audio_policy"
@ hardware/rockchip/audio/legacy_hal/audio_policy_hal.cpp
static int legacy_ap_dev_open(const hw_module_t* module, const char* name,
hw_device_t** device)
{
struct legacy_ap_device *dev;
if (strcmp(name, AUDIO_POLICY_INTERFACE) != 0)
return -EINVAL;
dev = (struct legacy_ap_device *)calloc(1, sizeof(*dev));
if (!dev)
return -ENOMEM;
dev->device.common.tag = HARDWARE_DEVICE_TAG;
dev->device.common.version = 0;
dev->device.common.module = const_cast<hw_module_t*>(module);
dev->device.common.close = legacy_ap_dev_close;
dev->device.create_audio_policy = create_legacy_ap;
dev->device.destroy_audio_policy = destroy_legacy_ap;
*device = &dev->device.common;
return 0;
}
static struct hw_module_methods_t legacy_ap_module_methods = {
.open = legacy_ap_dev_open
};
struct legacy_ap_module HAL_MODULE_INFO_SYM = {
.module = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.version_major = 1,
.version_minor = 0,
.id = AUDIO_POLICY_HARDWARE_MODULE_ID,
.name = "LEGACY Audio Policy HAL",
.author = "The Android Open Source Project",
.methods = &legacy_ap_module_methods,
.dso = NULL,
.reserved = {0},
},
},
};
@ hardware/libhardware/include/hardware/audio.h
#define AUDIO_HARDWARE_MODULE_ID "audio"
#define AUDIO_HARDWARE_MODULE_ID_PRIMARY "primary"
#define AUDIO_HARDWARE_MODULE_ID_A2DP "a2dp"
#define AUDIO_HARDWARE_MODULE_ID_USB "usb"
#define AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX "r_submix"
#define AUDIO_HARDWARE_MODULE_ID_CODEC_OFFLOAD "codec_offload"
@ hardware/rockchip/audio/legacy_hal/audio_hw_hal.cpp
#define LOG_TAG "legacy_audio_hw_hal"
#include <stdint.h>
#include <hardware/hardware.h>
#include <system/audio.h>
#include <hardware/audio.h>
#include <hardware_legacy/AudioHardwareInterface.h>
#include <hardware_legacy/AudioSystemLegacy.h>
static int legacy_adev_open(const hw_module_t* module, const char* name,
hw_device_t** device)
{
struct legacy_audio_device *ladev;
int ret;
if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
return -EINVAL;
ladev = (struct legacy_audio_device *)calloc(1, sizeof(*ladev));
if (!ladev)
return -ENOMEM;
ladev->device.common.tag = HARDWARE_DEVICE_TAG;
ladev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
ladev->device.common.module = const_cast<hw_module_t*>(module);
ladev->device.common.close = legacy_adev_close;
ladev->device.init_check = adev_init_check;
ladev->device.set_voice_volume = adev_set_voice_volume;
ladev->device.set_master_volume = adev_set_master_volume;
ladev->device.get_master_volume = adev_get_master_volume;
ladev->device.set_mode = adev_set_mode;
ladev->device.set_mic_mute = adev_set_mic_mute;
ladev->device.get_mic_mute = adev_get_mic_mute;
ladev->device.set_parameters = adev_set_parameters;
ladev->device.get_parameters = adev_get_parameters;
ladev->device.get_input_buffer_size = adev_get_input_buffer_size;
ladev->device.open_output_stream = adev_open_output_stream;
ladev->device.close_output_stream = adev_close_output_stream;
ladev->device.open_input_stream = adev_open_input_stream;
ladev->device.close_input_stream = adev_close_input_stream;
ladev->device.dump = adev_dump;
ladev->hwif = createAudioHardware();
if (!ladev->hwif) {
ret = -EIO;
goto err_create_audio_hw;
}
*device = &ladev->device.common;
return 0;
err_create_audio_hw:
free(ladev);
return ret;
}
static struct hw_module_methods_t legacy_audio_module_methods = {
open: legacy_adev_open
};
struct legacy_audio_module HAL_MODULE_INFO_SYM = {
module: {
common: {
tag: HARDWARE_MODULE_TAG,
module_api_version: AUDIO_MODULE_API_VERSION_0_1,
hal_api_version: HARDWARE_HAL_API_VERSION,
id: AUDIO_HARDWARE_MODULE_ID,
name: "LEGACY Audio HW HAL",
author: "The Android Open Source Project",
methods: &legacy_audio_module_methods,
dso : NULL,
reserved : {0},
},
},
};
Android7.0 以前版本采用 legacy 接口, 通过 AUDIO_POLICY_HARDWARE_MODULE_ID、AUDIO_HARDWARE_MODULE_ID 方式、 查找声卡路由策略和声卡hal层驱动。
2.1.2 采用 XML 配置文件方法
@ av/services/audiopolicy/manager/AudioPolicyFactory.cpp
#include "managerdefault/AudioPolicyManager.h"
namespace android {
extern "C" AudioPolicyInterface* createAudioPolicyManager(
AudioPolicyClientInterface *clientInterface)
{
return new AudioPolicyManager(clientInterface);
}
}
总结:
2.2> audioflinger 本地混音管理框架
@ frameworks/av/services/audioflinger/audioFlinger.hpp 这部分内容被编译成库 libaudioflinger.so,它是Audio系统的混音器服务部分。
virtual sp<IAudioTrack> createTrack(
audio_stream_type_t streamType,
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
size_t *pFrameCount,
audio_output_flags_t *flags,
const sp<IMemory>& sharedBuffer,
audio_io_handle_t output,
pid_t pid,
pid_t tid,
audio_session_t *sessionId,
int clientUid,
status_t *status ,
audio_port_handle_t portId);
virtual sp<IAudioRecord> openRecord(
audio_io_handle_t input,
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
const String16& opPackageName,
size_t *pFrameCount,
audio_input_flags_t *flags,
pid_t pid,
pid_t tid,
int clientUid,
audio_session_t *sessionId,
size_t *notificationFrames,
sp<IMemory>& cblk,
sp<IMemory>& buffers,
status_t *status ,
audio_port_handle_t portId);
virtual sp<IEffect> createEffect(
effect_descriptor_t *pDesc,
const sp<IEffectClient>& effectClient,
int32_t priority,
audio_io_handle_t io,
audio_session_t sessionId,
const String16& opPackageName,
pid_t pid,
status_t *status ,
int *id,
int *enabled);
virtual status_t openInput(audio_module_handle_t module,
audio_io_handle_t *input,
audio_config_t *config,
audio_devices_t *device,
const String8& address,
audio_source_t source,
audio_input_flags_t flags);
virtual uint32_t getPrimaryOutputSamplingRate();
virtual size_t getPrimaryOutputFrameCount();
virtual status_t createAudioPatch(const struct audio_patch *patch,
audio_patch_handle_t *handle);
sp<SyncEvent> createSyncEvent(AudioSystem::sync_event_t type,
audio_session_t triggerSession,
audio_session_t listenerSession,
sync_event_callback_t callBack,
const wp<RefBase>& cookie);
2.3> audiopolicy 音频策略管理框架
@frameworks/av/services/audiopolicy/service/AudioPolicyManager.cpp
virtual status_t setDeviceConnectionState(audio_devices_t device,
audio_policy_dev_state_t state,
const char *device_address,
const char *device_name);
virtual status_t handleDeviceConfigChange(audio_devices_t device,
const char *device_address,
const char *device_name);
virtual status_t createAudioPatch(const struct audio_patch *patch,
audio_patch_handle_t *handle);
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
audio_patch_handle_t *handle);
Android 7.0 弃用了 audio_policy.conf,并增加了对使用 XML 文件格式来定义音频拓扑的支持,这种文件格式更通俗易懂, 具有多种编辑和解析工具,并且足够灵活,可以描述复杂的音频拓扑。
注意:Android 7.0 仍支持使用 audio_policy.conf;默认使用这种旧版格式。要使用 XML 文件格式,需要在设备 Makefile 中 添加构建选项 USE_XML_AUDIO_POLICY_CONF := 1。
此程序获取 audio_policy_configuration.xml 生成音频设备管理对象,根据 xml 定义构建 audio policy 对象和 input、output 设备, 通过 dumpsys media.audio_policy 可以看到本机声卡设备和路由策略。
AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
:
#ifdef AUDIO_POLICY_TEST
Thread(false),
#endif
mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
mA2dpSuspended(false),
mAudioPortGeneration(1),
mBeaconMuteRefCount(0),
mBeaconPlayingRefCount(0),
mBeaconMuted(false),
mTtsOutputAvailable(false),
mMasterMono(false)
{
mUidCached = getuid();
mpClientInterface = clientInterface;
bool speakerDrcEnabled = false;
#ifdef USE_XML_AUDIO_POLICY_CONF
mVolumeCurves = new VolumeCurvesCollection();
AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices,
mDefaultOutputDevice, speakerDrcEnabled,
static_cast<VolumeCurvesCollection *>(mVolumeCurves));
PolicySerializer serializer;
if (serializer.deserialize(AUDIO_POLICY_XML_CONFIG_FILE, config) != NO_ERROR) {
#else
mVolumeCurves = new StreamDescriptorCollection();
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)) {
#endif
ALOGE("could not load audio policy configuration file, setting defaults");
config.setDefault();
}
mHDMIOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_AUX_DIGITAL);
mSPDIFOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPDIF);
audio_devices_t outputDeviceTypes = mAvailableOutputDevices.types();
audio_devices_t inputDeviceTypes = mAvailableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN;
for (size_t i = 0; i < mHwModules.size(); i++) {
mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->getName());
if (mHwModules[i]->mHandle == 0) {
ALOGW("could not open HW module %s", mHwModules[i]->getName());
continue;
}
for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
{
const sp<IOProfile> outProfile = mHwModules[i]->mOutputProfiles[j];
...
sp<SwAudioOutputDescriptor> outputDesc = new SwAudioOutputDescriptor(outProfile,
mpClientInterface);
const DeviceVector &supportedDevices = outProfile->getSupportedDevices();
const DeviceVector &devicesForType = supportedDevices.getDevicesFromType(profileType);
String8 address = devicesForType.size() > 0 ? devicesForType.itemAt(0)->mAddress
: String8("");
outputDesc->mDevice = profileType;
audio_config_t config = AUDIO_CONFIG_INITIALIZER;
config.sample_rate = outputDesc->mSamplingRate;
config.channel_mask = outputDesc->mChannelMask;
config.format = outputDesc->mFormat;
audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
status_t status = mpClientInterface->openOutput(outProfile->getModuleHandle(),
&output,
&config,
&outputDesc->mDevice,
address,
&outputDesc->mLatency,
outputDesc->mFlags);
if (status != NO_ERROR) {
ALOGW("Cannot open output stream for device %08x on hw module %s",
outputDesc->mDevice,
mHwModules[i]->getName());
} else {
outputDesc->mSamplingRate = config.sample_rate;
outputDesc->mChannelMask = config.channel_mask;
outputDesc->mFormat = config.format;
for (size_t k = 0; k < supportedDevices.size(); k++) {
ssize_t index = mAvailableOutputDevices.indexOf(supportedDevices[k]);
if (index >= 0 && !mAvailableOutputDevices[index]->isAttached()) {
mAvailableOutputDevices[index]->attach(mHwModules[i]);
}
}
if (mPrimaryOutput == 0 &&
outProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
mPrimaryOutput = outputDesc;
}
addOutput(output, outputDesc);
setOutputDevice(outputDesc,
outputDesc->mDevice,
true,
0,
NULL,
address.string());
}
}
for (size_t j = 0; j < mHwModules[i]->mInputProfiles.size(); j++)
{
const sp<IOProfile> inProfile = mHwModules[i]->mInputProfiles[j];
if (!inProfile->hasSupportedDevices()) {
ALOGW("Input profile contains no device on module %s", mHwModules[i]->getName());
continue;
}
audio_devices_t profileType = inProfile->getSupportedDeviceForType(inputDeviceTypes);
if ((profileType & inputDeviceTypes) == 0) {
continue;
}
sp<AudioInputDescriptor> inputDesc =
new AudioInputDescriptor(inProfile);
inputDesc->mDevice = profileType;
DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromType(profileType);
String8 address = inputDevices.size() > 0 ? inputDevices.itemAt(0)->mAddress
: String8("");
ALOGV(" for input device 0x%x using address %s", profileType, address.string());
ALOGE_IF(inputDevices.size() == 0, "Input device list is empty!");
audio_config_t config = AUDIO_CONFIG_INITIALIZER;
config.sample_rate = inputDesc->mSamplingRate;
config.channel_mask = inputDesc->mChannelMask;
config.format = inputDesc->mFormat;
audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
status_t status = mpClientInterface->openInput(inProfile->getModuleHandle(),
&input,
&config,
&inputDesc->mDevice,
address,
AUDIO_SOURCE_MIC,
AUDIO_INPUT_FLAG_NONE);
if (status == NO_ERROR) {
const DeviceVector &supportedDevices = inProfile->getSupportedDevices();
for (size_t k = 0; k < supportedDevices.size(); k++) {
ssize_t index = mAvailableInputDevices.indexOf(supportedDevices[k]);
if (index >= 0) {
sp<DeviceDescriptor> devDesc = mAvailableInputDevices[index];
if (!devDesc->isAttached()) {
devDesc->attach(mHwModules[i]);
devDesc->importAudioPort(inProfile);
}
}
}
mpClientInterface->closeInput(input);
} else {
ALOGW("Cannot open input stream for device %08x on hw module %s",
inputDesc->mDevice,
mHwModules[i]->getName());
}
}
}
}
此 audio_policy_configuration.xml 包含 usb、a2dp 和 r_submix 策略配置文件 xml , 这些文件会拷贝至 system/etc/ 文件夹中。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
<!-- version section contains a “version” tag in the form “major.minor” e.g version=”1.0” -->
<!-- Global configuration Decalaration -->
<globalConfiguration speaker_drc_enabled="true"/>
<modules>
<!-- Primary Audio HAL -->
<module name="primary" halVersion="3.0">
<attachedDevices>
<item>Speaker</item>
<item>Built-In Mic</item>
<item>Built-In Back Mic</item>
</attachedDevices>
<defaultOutputDevice>Speaker</defaultOutputDevice>
<mixPorts>
<mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
</mixPort>
<mixPort name="deep_buffer" role="source"
flags="AUDIO_OUTPUT_FLAG_DEEP_BUFFER">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
</mixPort>
<mixPort name="compressed_offload" role="source"
flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_NON_BLOCKING">
<profile name="" format="AUDIO_FORMAT_MP3"
samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/>
<profile name="" format="AUDIO_FORMAT_AAC"
samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/>
<profile name="" format="AUDIO_FORMAT_AAC_LC"
samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/>
</mixPort>
<mixPort name="voice_tx" role="source">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
</mixPort>
<mixPort name="primary input" role="sink">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
</mixPort>
<mixPort name="voice_rx" role="sink">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
</mixPort>
</mixPorts>
<devicePorts>
<!-- Output devices declaration, i.e. Sink DEVICE PORT -->
<devicePort tagName="Earpiece" type="AUDIO_DEVICE_OUT_EARPIECE" role="sink">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
</devicePort>
<devicePort tagName="Speaker" role="sink" type="AUDIO_DEVICE_OUT_SPEAKER" address="">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
<gains>
<gain name="gain_1" mode="AUDIO_GAIN_MODE_JOINT"
minValueMB="-8400"
maxValueMB="4000"
defaultValueMB="0"
stepValueMB="100"/>
</gains>
</devicePort>
<devicePort tagName="Wired Headset" type="AUDIO_DEVICE_OUT_WIRED_HEADSET" role="sink">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
</devicePort>
<devicePort tagName="Wired Headphones" type="AUDIO_DEVICE_OUT_WIRED_HEADPHONE" role="sink">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
</devicePort>
<devicePort tagName="BT SCO" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO" role="sink">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
</devicePort>
<devicePort tagName="BT SCO Headset" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET" role="sink">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
</devicePort>
<devicePort tagName="BT SCO Car Kit" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT" role="sink">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
</devicePort>
<devicePort tagName="Telephony Tx" type="AUDIO_DEVICE_OUT_TELEPHONY_TX" role="sink">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
</devicePort>
<devicePort tagName="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
</devicePort>
<devicePort tagName="Built-In Back Mic" type="AUDIO_DEVICE_IN_BACK_MIC" role="source">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
</devicePort>
<devicePort tagName="Wired Headset Mic" type="AUDIO_DEVICE_IN_WIRED_HEADSET" role="source">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000"
channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/>
</devicePort>
<devicePort tagName="BT SCO Headset Mic" type="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET" role="source">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
</devicePort>
<devicePort tagName="Telephony Rx" type="AUDIO_DEVICE_IN_TELEPHONY_RX" role="source">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
</devicePort>
</devicePorts>
<!-- route declaration, i.e. list all available sources for a given sink -->
<routes>
<route type="mix" sink="Earpiece"
sources="primary output,deep_buffer,BT SCO Headset Mic"/>
<route type="mix" sink="Speaker"
sources="primary output,deep_buffer,compressed_offload,BT SCO Headset Mic,Telephony Rx"/>
<route type="mix" sink="Wired Headset"
sources="primary output,deep_buffer,compressed_offload,BT SCO Headset Mic,Telephony Rx"/>
<route type="mix" sink="Wired Headphones"
sources="primary output,deep_buffer,compressed_offload,BT SCO Headset Mic,Telephony Rx"/>
<route type="mix" sink="Telephony Tx"
sources="voice_tx"/>
<route type="mix" sink="primary input"
sources="Built-In Mic,Built-In Back Mic,Wired Headset Mic,BT SCO Headset Mic"/>
<route type="mix" sink="Telephony Tx"
sources="Built-In Mic,Built-In Back Mic,Wired Headset Mic,BT SCO Headset Mic"/>
<route type="mix" sink="voice_rx"
sources="Telephony Rx"/>
</routes>
</module>
<!-- HDMI Audio HAL -->
<module description="HDMI Audio HAL" name="hdmi" version="2.0">
<mixPorts>
<mixPort name="hdmi output" role="source">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT" samplingRates="48000"/>
</mixPort>
</mixPorts>
<devicePorts>
<devicePort tagName="HDMI Out" type="AUDIO_DEVICE_OUT_AUX_DIGITAL" role="sink">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
</devicePort>
</devicePorts>
<routes>
<route type="mix" sink="HDMI Out"
sources="hdmi output"/>
</routes>
</module>
<!-- A2dp Audio HAL --> <xi:include href="a2dp_audio_policy_configuration.xml"/>
<!-- Usb Audio HAL --> <xi:include href="usb_audio_policy_configuration.xml"/>
<!-- Remote Submix Audio HAL --> <xi:include href="r_submix_audio_policy_configuration.xml"/>
</modules> <!-- End of Modules section -->
<!-- Volume section -->
<xi:include href="audio_policy_volumes.xml"/>
<xi:include href="default_volume_tables.xml"/>
<!-- End of Volume section -->
</audioPolicyConfiguration>
总结: (1). 在 AudioPolicyManager(AudioPolicyClientInterface *clientInterface) 构建函数中,根据 xml 配置文件 module 生成 mHwModules[] 设备对象,多个 moduel 就生成多个 mHwModules[] 对象;
(2). 把 mHwModules[] 设备中的 输入与输出sink,添加到所有 mAvailableOutputDevices 和 mAvailableInputDevices 实例中;
(3). 把所有 mHwModules[] 设备中sink取交集,作为音频输入与输出设备接口;
(4). 每各 mHwModules[] 都由 route 属性,提取路由策略相关信息。
rk3288:/ # dumpsys media.audio_policy
AudioPolicyManager Dump: 0xb4d3e200
Primary Output: 13
Phone state: 0
Force use for communications 0
Force use for media 0
Force use for record 0
Force use for dock 8
Force use for system 0
Force use for hdmi system audio 0
Force use for encoded surround output 0
TTS output not available
Master mono: off
- Available output devices:
Device 1:
- id: 1
- tag name: Speaker
- type: AUDIO_DEVICE_OUT_SPEAKER
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:48000
- channel masks:0x0003
- gains:
Gain 1:
- mode: 00000001
- channel_mask: 00000000
- min_value: 0 mB
- max_value: 4000 mB
- default_value: 0 mB
- step_value: 100 mB
- min_ramp_ms: 0 ms
- max_ramp_ms: 0 ms
- Available input devices:
Device 1:
- id: 4
- tag name: Built-In Mic
- type: AUDIO_DEVICE_IN_BUILTIN_MIC
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
- channel masks:0x000c, 0x0010, 0x0030
Device 2:
- id: 5
- tag name: Built-In Back Mic
- type: AUDIO_DEVICE_IN_BACK_MIC
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
- channel masks:0x000c, 0x0010, 0x0030
Device 3:
- id: 6
- tag name: Remote Submix In
- type: AUDIO_DEVICE_IN_REMOTE_SUBMIX
- address: 0
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:48000
- channel masks:0x000c
HW Modules dump:
- HW Module 1:
- name: primary
- handle: 10
- version: 2.5
- outputs:
output 0:
- name: primary output
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:48000
- channel masks:0x0003
- flags: 0x0002
- Supported devices:
Device 1:
- tag name: Earpiece
- type: AUDIO_DEVICE_OUT_EARPIECE
Device 2:
- id: 1
- tag name: Speaker
- type: AUDIO_DEVICE_OUT_SPEAKER
Device 3:
- tag name: Wired Headset
- type: AUDIO_DEVICE_OUT_WIRED_HEADSET
Device 4:
- tag name: Wired Headphones
- type: AUDIO_DEVICE_OUT_WIRED_HEADPHONE
output 1:
- name: deep_buffer
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:48000
- channel masks:0x0003
- flags: 0x0008
- Supported devices:
Device 1:
- tag name: Earpiece
- type: AUDIO_DEVICE_OUT_EARPIECE
Device 2:
- id: 1
- tag name: Speaker
- type: AUDIO_DEVICE_OUT_SPEAKER
Device 3:
- tag name: Wired Headset
- type: AUDIO_DEVICE_OUT_WIRED_HEADSET
Device 4:
- tag name: Wired Headphones
- type: AUDIO_DEVICE_OUT_WIRED_HEADPHONE
output 2:
- name: compressed_offload
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_MP3
- sampling rates:8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
- channel masks:0x0001, 0x0003
Profile 1:
- format: AUDIO_FORMAT_AAC
- sampling rates:8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
- channel masks:0x0001, 0x0003
Profile 2:
- format: AUDIO_FORMAT_AAC_LC
- sampling rates:8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
- channel masks:0x0001, 0x0003
- flags: 0x0031
- Supported devices:
Device 1:
- id: 1
- tag name: Speaker
- type: AUDIO_DEVICE_OUT_SPEAKER
Device 2:
- tag name: Wired Headset
- type: AUDIO_DEVICE_OUT_WIRED_HEADSET
Device 3:
- tag name: Wired Headphones
- type: AUDIO_DEVICE_OUT_WIRED_HEADPHONE
output 3:
- name: voice_tx
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:8000, 16000
- channel masks:0x0001
- flags: 0x0000
- Supported devices:
Device 1:
- tag name: Telephony Tx
- type: AUDIO_DEVICE_OUT_TELEPHONY_TX
- inputs:
input 0:
- name: primary input
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
- channel masks:0x000c, 0x0010, 0x0030
- flags: 0x0000
- Supported devices:
Device 1:
- id: 4
- tag name: Built-In Mic
- type: AUDIO_DEVICE_IN_BUILTIN_MIC
Device 2:
- id: 5
- tag name: Built-In Back Mic
- type: AUDIO_DEVICE_IN_BACK_MIC
Device 3:
- tag name: Wired Headset Mic
- type: AUDIO_DEVICE_IN_WIRED_HEADSET
Device 4:
- tag name: BT SCO Headset Mic
- type: AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET
input 1:
- name: voice_rx
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:8000, 16000
- channel masks:0x0010
- flags: 0x0000
- Supported devices:
Device 1:
- tag name: Telephony Rx
- type: AUDIO_DEVICE_IN_TELEPHONY_RX
- Declared devices:
Device 1:
- tag name: Earpiece
- type: AUDIO_DEVICE_OUT_EARPIECE
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:48000
- channel masks:0x0010
Device 2:
- id: 1
- tag name: Speaker
- type: AUDIO_DEVICE_OUT_SPEAKER
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:48000
- channel masks:0x0003
- gains:
Gain 1:
- mode: 00000001
- channel_mask: 00000000
- min_value: 0 mB
- max_value: 4000 mB
- default_value: 0 mB
- step_value: 100 mB
- min_ramp_ms: 0 ms
- max_ramp_ms: 0 ms
Device 3:
- tag name: Wired Headset
- type: AUDIO_DEVICE_OUT_WIRED_HEADSET
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:48000
- channel masks:0x0003
Device 4:
- tag name: Wired Headphones
- type: AUDIO_DEVICE_OUT_WIRED_HEADPHONE
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:48000
- channel masks:0x0003
Device 5:
- tag name: BT SCO
- type: AUDIO_DEVICE_OUT_BLUETOOTH_SCO
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:8000, 16000
- channel masks:0x0001
Device 6:
- tag name: BT SCO Headset
- type: AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:8000, 16000
- channel masks:0x0001
Device 7:
- tag name: BT SCO Car Kit
- type: AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:8000, 16000
- channel masks:0x0001
Device 8:
- tag name: Telephony Tx
- type: AUDIO_DEVICE_OUT_TELEPHONY_TX
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:8000, 16000
- channel masks:0x0001
Device 9:
- id: 4
- tag name: Built-In Mic
- type: AUDIO_DEVICE_IN_BUILTIN_MIC
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
- channel masks:0x000c, 0x0010, 0x0030
Device 10:
- id: 5
- tag name: Built-In Back Mic
- type: AUDIO_DEVICE_IN_BACK_MIC
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
- channel masks:0x000c, 0x0010, 0x0030
Device 11:
- tag name: Wired Headset Mic
- type: AUDIO_DEVICE_IN_WIRED_HEADSET
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
- channel masks:0x000c, 0x0010, 0x0030
Device 12:
- tag name: BT SCO Headset Mic
- type: AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:8000, 16000
- channel masks:0x0010
Device 13:
- tag name: Telephony Rx
- type: AUDIO_DEVICE_IN_TELEPHONY_RX
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:8000, 16000
- channel masks:0x0010
Audio Routes (8):
- Route 1:
- Type: Mix
- Sink: Earpiece
- Sources:
primary output
deep_buffer
BT SCO Headset Mic
- Route 2:
- Type: Mix
- Sink: Speaker
- Sources:
primary output
deep_buffer
compressed_offload
BT SCO Headset Mic
Telephony Rx
- Route 3:
- Type: Mix
- Sink: Wired Headset
- Sources:
primary output
deep_buffer
compressed_offload
BT SCO Headset Mic
Telephony Rx
- Route 4:
- Type: Mix
- Sink: Wired Headphones
- Sources:
primary output
deep_buffer
compressed_offload
BT SCO Headset Mic
Telephony Rx
- Route 5:
- Type: Mix
- Sink: Telephony Tx
- Sources:
voice_tx
- Route 6:
- Type: Mix
- Sink: primary input
- Sources:
Built-In Mic
Built-In Back Mic
Wired Headset Mic
BT SCO Headset Mic
- Route 7:
- Type: Mix
- Sink: Telephony Tx
- Sources:
Built-In Mic
Built-In Back Mic
Wired Headset Mic
BT SCO Headset Mic
- Route 8:
- Type: Mix
- Sink: voice_rx
- Sources:
Telephony Rx
- HW Module 2:
- name: hdmi
- handle: 0
- version: 2.0
- outputs:
output 0:
- name: hdmi output
- Profiles:
Profile 0:[dynamic channels]
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:48000
- flags: 0x0000
- Supported devices:
Device 1:
- tag name: HDMI Out
- type: AUDIO_DEVICE_OUT_AUX_DIGITAL
- Declared devices:
Device 1:
- tag name: HDMI Out
- type: AUDIO_DEVICE_OUT_AUX_DIGITAL
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:48000
- channel masks:0x0003
Audio Routes (1):
- Route 1:
- Type: Mix
- Sink: HDMI Out
- Sources:
hdmi output
- HW Module 3:
- name: a2dp
- handle: 18
- version: 2.3
- outputs:
output 0:
- name: a2dp output
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:44100
- channel masks:0x0003
- flags: 0x0000
- Supported devices:
Device 1:
- tag name: BT A2DP Out
- type: AUDIO_DEVICE_OUT_BLUETOOTH_A2DP
Device 2:
- tag name: BT A2DP Headphones
- type: AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES
Device 3:
- tag name: BT A2DP Speaker
- type: AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER
- inputs:
input 0:
- name: a2dp input
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:44100, 48000
- channel masks:0x000c, 0x0010
- flags: 0x0000
- Supported devices:
Device 1:
- tag name: BT A2DP In
- type: AUDIO_DEVICE_IN_BLUETOOTH_A2DP
- Declared devices:
Device 1:
- tag name: BT A2DP Out
- type: AUDIO_DEVICE_OUT_BLUETOOTH_A2DP
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:44100
- channel masks:0x0003
Device 2:
- tag name: BT A2DP Headphones
- type: AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:44100
- channel masks:0x0003
Device 3:
- tag name: BT A2DP Speaker
- type: AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:44100
- channel masks:0x0003
Device 4:
- tag name: BT A2DP In
- type: AUDIO_DEVICE_IN_BLUETOOTH_A2DP
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:44100, 48000
- channel masks:0x000c, 0x0010
Audio Routes (4):
- Route 1:
- Type: Mix
- Sink: BT A2DP Out
- Sources:
a2dp output
- Route 2:
- Type: Mix
- Sink: BT A2DP Headphones
- Sources:
a2dp output
- Route 3:
- Type: Mix
- Sink: BT A2DP Speaker
- Sources:
a2dp output
- Route 4:
- Type: Mix
- Sink: a2dp input
- Sources:
BT A2DP In
- HW Module 4:
- name: usb
- handle: 26
- version: 2.2
- outputs:
output 0:
- name: usb_accessory output
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:44100
- channel masks:0x0003
- flags: 0x0000
- Supported devices:
Device 1:
- tag name: USB Host Out
- type: AUDIO_DEVICE_OUT_USB_ACCESSORY
output 1:
- name: usb_device output
- Profiles:
Profile 0:[dynamic format][dynamic channels][dynamic rates]
- flags: 0x0000
- Supported devices:
Device 1:
- tag name: USB Device Out
- type: AUDIO_DEVICE_OUT_USB_DEVICE
- inputs:
input 0:
- name: usb_device input
- Profiles:
Profile 0:[dynamic format][dynamic channels][dynamic rates]
- flags: 0x0000
- Supported devices:
Device 1:
- tag name: USB Device In
- type: AUDIO_DEVICE_IN_USB_DEVICE
- Declared devices:
Device 1:
- tag name: USB Host Out
- type: AUDIO_DEVICE_OUT_USB_ACCESSORY
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:44100
- channel masks:0x0003
Device 2:
- tag name: USB Device Out
- type: AUDIO_DEVICE_OUT_USB_DEVICE
- Profiles:
Profile 0:[dynamic format][dynamic channels][dynamic rates]
Device 3:
- tag name: USB Device In
- type: AUDIO_DEVICE_IN_USB_DEVICE
- Profiles:
Profile 0:[dynamic format][dynamic channels][dynamic rates]
Audio Routes (3):
- Route 1:
- Type: Mix
- Sink: USB Host Out
- Sources:
usb_accessory output
- Route 2:
- Type: Mix
- Sink: USB Device Out
- Sources:
usb_device output
- Route 3:
- Type: Mix
- Sink: usb_device input
- Sources:
USB Device In
- HW Module 5:
- name: r_submix
- handle: 34
- version: 2.1
- outputs:
output 0:
- name: r_submix output
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:48000
- channel masks:0x0003
- flags: 0x0000
- Supported devices:
Device 1:
- tag name: Remote Submix Out
- type: AUDIO_DEVICE_OUT_REMOTE_SUBMIX
- address: 0
- inputs:
input 0:
- name: r_submix input
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:48000
- channel masks:0x000c
- flags: 0x0000
- Supported devices:
Device 1:
- id: 6
- tag name: Remote Submix In
- type: AUDIO_DEVICE_IN_REMOTE_SUBMIX
- address: 0
- Declared devices:
Device 1:
- tag name: Remote Submix Out
- type: AUDIO_DEVICE_OUT_REMOTE_SUBMIX
- address: 0
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:48000
- channel masks:0x0003
Device 2:
- id: 6
- tag name: Remote Submix In
- type: AUDIO_DEVICE_IN_REMOTE_SUBMIX
- address: 0
- Profiles:
Profile 0:
- format: AUDIO_FORMAT_PCM_16_BIT
- sampling rates:48000
- channel masks:0x000c
Audio Routes (2):
- Route 1:
- Type: Mix
- Sink: Remote Submix Out
- Sources:
r_submix output
- Route 2:
- Type: Mix
- Sink: r_submix input
- Sources:
Remote Submix In
Outputs dump:
- Output 13 dump:
Latency: 115
Flags 00000002
ID: 2
Sampling rate: 48000
Format: 00000001
Channels: 00000003
Devices 00000002
Stream volume refCount muteCount
00 -24.000 00 00
01 -758.000 00 00
02 -758.000 00 00
03 -758.000 00 00
04 -758.000 00 00
05 -758.000 00 00
06 -1.000 00 00
07 -758.000 00 00
08 -758.000 00 00
09 0.000 00 01
10 -758.000 00 00
11 0.000 00 00
12 -1.000 00 00
- Output 21 dump:
Latency: 743
Flags 00000008
ID: 3
Sampling rate: 48000
Format: 00000001
Channels: 00000003
Devices 00000002
Stream volume refCount muteCount
00 -24.000 00 00
01 -758.000 00 00
02 -758.000 00 00
03 -758.000 00 00
04 -758.000 00 00
05 -758.000 00 00
06 -1.000 00 00
07 -758.000 00 00
08 -758.000 00 00
09 0.000 00 01
10 -758.000 00 00
11 0.000 00 00
12 -1.000 00 00
Inputs dump:
Streams dump:
Stream Can be muted Index Min Index Max Index Cur [device : index]...
00 true 01 05 0002 : 05, 0004 : 05, 0008 : 05, 0400 : 05, 40000000 : 04,
01 true 00 07 0002 : 07, 0004 : 07, 0008 : 07, 0400 : 07, 40000000 : 05,
02 true 00 07 0002 : 07, 0004 : 07, 0008 : 07, 0400 : 07, 40000000 : 05,
03 true 00 15 0002 : 15, 0004 : 15, 0008 : 15, 0400 : 15, 40000000 : 11,
04 true 00 07 0002 : 07, 0004 : 07, 0008 : 07, 0400 : 07, 40000000 : 06,
05 true 00 07 0002 : 07, 0004 : 07, 0008 : 07, 0400 : 07, 40000000 : 05,
06 true 00 15 0002 : 15, 0004 : 15, 0008 : 15, 0400 : 15, 40000000 : 07,
07 true 00 07 0002 : 07, 0004 : 07, 0008 : 07, 0400 : 07, 40000000 : 05,
08 true 00 15 0002 : 15, 0004 : 15, 0008 : 15, 0400 : 15, 40000000 : 11,
09 true 00 15 0002 : 15, 0004 : 15, 0008 : 15, 0400 : 15, 40000000 : 11,
10 true 00 15 0002 : 15, 0004 : 15, 0008 : 15, 0400 : 15, 40000000 : 11,
11 true 00 01 40000000 : 00,
12 true 00 01 40000000 : 00,
Volume Curves for Use Cases (aka Stream types) dump:
AUDIO_STREAM_VOICE_CALL (00): Curve points for device category (index, attenuation in millibel)
DEVICE_CATEGORY_HEADSET : {( 0, -4200), ( 33, -2800), ( 66, -1400), (100, 0) }
DEVICE_CATEGORY_SPEAKER : {( 0, -2400), ( 33, -1600), ( 66, -800), (100, 0) }
DEVICE_CATEGORY_EARPIECE : {( 0, -2400), ( 33, -1600), ( 66, -800), (100, 0) }
DEVICE_CATEGORY_EXT_MEDIA : {( 1, -5800), ( 20, -4000), ( 60, -1700), (100, 0) }
AUDIO_STREAM_SYSTEM (01): Curve points for device category (index, attenuation in millibel)
DEVICE_CATEGORY_HEADSET : {( 1, -3000), ( 33, -2600), ( 66, -2200), (100, -1800) }
DEVICE_CATEGORY_SPEAKER : {( 1, -2400), ( 33, -1800), ( 66, -1200), (100, -600) }
DEVICE_CATEGORY_EARPIECE : {( 1, -2400), ( 33, -1800), ( 66, -1200), (100, -600) }
DEVICE_CATEGORY_EXT_MEDIA : {( 1, -5800), ( 20, -4000), ( 60, -2100), (100, -1000) }
AUDIO_STREAM_RING (02): Curve points for device category (index, attenuation in millibel)
DEVICE_CATEGORY_HEADSET : {( 1, -4950), ( 33, -3350), ( 66, -1700), (100, 0) }
DEVICE_CATEGORY_SPEAKER : {( 1, -2970), ( 33, -2010), ( 66, -1020), (100, 0) }
DEVICE_CATEGORY_EARPIECE : {( 1, -4950), ( 33, -3350), ( 66, -1700), (100, 0) }
DEVICE_CATEGORY_EXT_MEDIA : {( 1, -5800), ( 20, -4000), ( 60, -2100), (100, -1000) }
AUDIO_STREAM_MUSIC (03): Curve points for device category (index, attenuation in millibel)
DEVICE_CATEGORY_HEADSET : {( 1, -5800), ( 20, -4000), ( 60, -1700), (100, 0) }
DEVICE_CATEGORY_SPEAKER : {( 1, -5800), ( 20, -4000), ( 60, -1700), (100, 0) }
DEVICE_CATEGORY_EARPIECE : {( 1, -5800), ( 20, -4000), ( 60, -1700), (100, 0) }
DEVICE_CATEGORY_EXT_MEDIA : {( 1, -5800), ( 20, -4000), ( 60, -1700), (100, 0) }
AUDIO_STREAM_ALARM (04): Curve points for device category (index, attenuation in millibel)
DEVICE_CATEGORY_HEADSET : {( 1, -4950), ( 33, -3350), ( 66, -1700), (100, 0) }
DEVICE_CATEGORY_SPEAKER : {( 1, -2970), ( 33, -2010), ( 66, -1020), (100, 0) }
DEVICE_CATEGORY_EARPIECE : {( 1, -4950), ( 33, -3350), ( 66, -1700), (100, 0) }
DEVICE_CATEGORY_EXT_MEDIA : {( 1, -5800), ( 20, -4000), ( 60, -2100), (100, -1000) }
AUDIO_STREAM_NOTIFICATION (05): Curve points for device category (index, attenuation in millibel)
DEVICE_CATEGORY_HEADSET : {( 1, -4950), ( 33, -3350), ( 66, -1700), (100, 0) }
DEVICE_CATEGORY_SPEAKER : {( 1, -2970), ( 33, -2010), ( 66, -1020), (100, 0) }
DEVICE_CATEGORY_EARPIECE : {( 1, -4950), ( 33, -3350), ( 66, -1700), (100, 0) }
DEVICE_CATEGORY_EXT_MEDIA : {( 1, -5800), ( 20, -4000), ( 60, -2100), (100, -1000) }
AUDIO_STREAM_BLUETOOTH_SCO (06): Curve points for device category (index, attenuation in millibel)
DEVICE_CATEGORY_HEADSET : {( 0, -4200), ( 33, -2800), ( 66, -1400), (100, 0) }
DEVICE_CATEGORY_SPEAKER : {( 0, -2400), ( 33, -1600), ( 66, -800), (100, 0) }
DEVICE_CATEGORY_EARPIECE : {( 0, -4200), ( 33, -2800), ( 66, -1400), (100, 0) }
DEVICE_CATEGORY_EXT_MEDIA : {( 1, -5800), ( 20, -4000), ( 60, -1700), (100, 0) }
AUDIO_STREAM_ENFORCED_AUDIBLE (07): Curve points for device category (index, attenuation in millibel)
DEVICE_CATEGORY_HEADSET : {( 1, -3000), ( 33, -2600), ( 66, -2200), (100, -1800) }
DEVICE_CATEGORY_SPEAKER : {( 1, -2400), ( 33, -1800), ( 66, -1200), (100, -600) }
DEVICE_CATEGORY_EARPIECE : {( 1, -2400), ( 33, -1800), ( 66, -1200), (100, -600) }
DEVICE_CATEGORY_EXT_MEDIA : {( 1, -5800), ( 20, -4000), ( 60, -2100), (100, -1000) }
AUDIO_STREAM_DTMF (08): Curve points for device category (index, attenuation in millibel)
DEVICE_CATEGORY_HEADSET : {( 1, -3000), ( 33, -2600), ( 66, -2200), (100, -1800) }
DEVICE_CATEGORY_SPEAKER : {( 1, -2400), ( 33, -1800), ( 66, -1200), (100, -600) }
DEVICE_CATEGORY_EARPIECE : {( 1, -2400), ( 33, -1800), ( 66, -1200), (100, -600) }
DEVICE_CATEGORY_EXT_MEDIA : {( 1, -5800), ( 20, -4000), ( 60, -2100), (100, -1000) }
AUDIO_STREAM_TTS (09): Curve points for device category (index, attenuation in millibel)
DEVICE_CATEGORY_HEADSET : {( 0, -9600), (100, -9600) }
DEVICE_CATEGORY_SPEAKER : {( 0, 0), (100, 0) }
DEVICE_CATEGORY_EARPIECE : {( 0, -9600), (100, -9600) }
DEVICE_CATEGORY_EXT_MEDIA : {( 0, -9600), (100, -9600) }
AUDIO_STREAM_ACCESSIBILITY (10): Curve points for device category (index, attenuation in millibel)
DEVICE_CATEGORY_HEADSET : {( 1, -5800), ( 20, -4000), ( 60, -1700), (100, 0) }
DEVICE_CATEGORY_SPEAKER : {( 1, -5800), ( 20, -4000), ( 60, -1700), (100, 0) }
DEVICE_CATEGORY_EARPIECE : {( 1, -5800), ( 20, -4000), ( 60, -1700), (100, 0) }
DEVICE_CATEGORY_EXT_MEDIA : {( 1, -5800), ( 20, -4000), ( 60, -1700), (100, 0) }
AUDIO_STREAM_REROUTING (11): Curve points for device category (index, attenuation in millibel)
DEVICE_CATEGORY_HEADSET : {( 0, 0), (100, 0) }
DEVICE_CATEGORY_SPEAKER : {( 0, 0), (100, 0) }
DEVICE_CATEGORY_EARPIECE : {( 0, 0), (100, 0) }
DEVICE_CATEGORY_EXT_MEDIA : {( 0, 0), (100, 0) }
AUDIO_STREAM_PATCH (12): Curve points for device category (index, attenuation in millibel)
DEVICE_CATEGORY_HEADSET : {( 0, 0), (100, 0) }
DEVICE_CATEGORY_SPEAKER : {( 0, 0), (100, 0) }
DEVICE_CATEGORY_EARPIECE : {( 0, 0), (100, 0) }
DEVICE_CATEGORY_EXT_MEDIA : {( 0, 0), (100, 0) }
Total Effects CPU: 0.000000 MIPS, Total Effects memory: 0 KB, Max memory used: 0 KB
Registered effects:
Audio Patches:
Audio patch 1:
- handle: 1
- audio flinger handle: 12
- owner uid: 1041
- 1 sources:
- Mix ID 2 I/O handle 13
- 1 sinks:
- Device ID 1 AUDIO_DEVICE_OUT_SPEAKER
Audio patch 2:
- handle: 2
- audio flinger handle: 20
- owner uid: 1041
- 1 sources:
- Mix ID 3 I/O handle 21
- 1 sinks:
- Device ID 1 AUDIO_DEVICE_OUT_SPEAKER
2.3.1> 如何通过 xml 配置文件对应 hw_hal 驱动?
mpClientInterface 是入口参数传递过来,此 loadHwModule() 是虚函数,在 AudioPolicyClientImpl.cpp 中被实现;
audio_module_handle_t AudioPolicyService::AudioPolicyClient::loadHwModule(const char *name)
{
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
if (af == 0) {
ALOGW("%s: could not get AudioFlinger", __func__);
return AUDIO_MODULE_HANDLE_NONE;
}
return af->loadHwModule(name);
}
@ AudioSystem::get_audio_flinger() 函数内容如下
const sp<IAudioFlinger> AudioSystem::get_audio_flinger()
{
sp<IAudioFlinger> af;
sp<AudioFlingerClient> afc;
{
Mutex::Autolock _l(gLock);
if (gAudioFlinger == 0) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
binder = sm->getService(String16("media.audio_flinger"));
if (binder != 0)
break;
ALOGW("AudioFlinger not published, waiting...");
usleep(500000);
} while (true);
if (gAudioFlingerClient == NULL) {
gAudioFlingerClient = new AudioFlingerClient();
} else {
if (gAudioErrorCallback) {
gAudioErrorCallback(NO_ERROR);
}
}
binder->linkToDeath(gAudioFlingerClient);
gAudioFlinger = interface_cast<IAudioFlinger>(binder);
LOG_ALWAYS_FATAL_IF(gAudioFlinger == 0);
afc = gAudioFlingerClient;
}
af = gAudioFlinger;
}
if (afc != 0) {
af->registerClient(afc);
}
return af;
}
@ hardware/rockchip/tinyalsa_hal/Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := audio.primary.$(TARGET_BOARD_HARDWARE)
LOCAL_PROPRIETARY_MODULE := true
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_SRC_FILES := \
audio_setting.c \
audio_bitstream.c \
audio_hw.c \
alsa_route.c \
alsa_mixer.c \
voice_preprocess.c \
audio_hw_hdmi.c
LOCAL_C_INCLUDES += \
external/tinyalsa/include \
$(call include-path-for, audio-utils) \
$(call include-path-for, audio-route) \
$(call include-path-for, speex)
至此为止,我们捋顺 AudioPolicyManager 是如何装载厂商编写 HAL 驱动程序。
在 AudioPolicyManager::AudioPolicyManager() 构造函数中, 解析 xml 配置文件将生成 4 个 HwModule[] 对象,分别是: primary、a2dp、usb 和 r_submix 模块。
总结:
-
AudioPolicyService继承了IAudioPolicyService接口,这样AudioPolicyService就可以基于Android的Binder机制,向外部提供服务; -
AudioPolicyService同时也继承了AudioPolicyClientInterface类,他有一个AudioPolicyInterface类的成员指针mpPolicyManager, 实际上就是指向了AudioPolicyManager; -
AudioPolicyManager类继承了AudioPolicyInterface类以便向AudioPolicyService提供服务,反过来同时还有一个AudioPolicyClientInterface指针, 该指针在构造函数中被初始化,指向了AudioPolicyService,实际上,AudioPolicyService是通过成员指针mpPolicyManager访问AudioPolicyManager, 而AudioPolicyManager则通过AudioPolicyClientInterface(mpClientInterface)访问AudioPolicyService; -
AudioPolicyService有一个内部线程类AudioCommandThread,顾名思义,所有的命令(音量控制,输入、输出的切换等)最终都会在该线程中排队执行; -
音频系统为音频设备定义了一个枚举:AudioSystem::audio_devices,例如:DEVICE_OUT_SPEAKER,DEVICE_OUT_WIRED_HEADPHONE, DEVICE_OUT_BLUETOOTH_A2DP,DEVICE_IN_BUILTIN_MIC,DEVICE_IN_VOICE_CALL等等,每一个枚举值其实对应一个32bit整数的某一个位, 所以这些值是可以进行位或操作的,例如我希望同时打开扬声器和耳机,可以这样配置:
newDevice = DEVICE_OUT_SPEAKER | DEVICE_OUT_WIRED_HEADPHONE;
setOutputDevice(mHardwareOutput, newDevice);
- AudioPolicyManager中有两个成员变量:mAvailableOutputDevices和mAvailableInputDevices,他们记录了当前可用的输入和输出设备,
当系统检测到耳机或者蓝牙已连接好时,会调用AudioPolicyManager的成员函数;
status_t AudioPolicyManager::setDeviceConnectionState(AudioSystem::audio_devices device,
AudioSystem::device_connection_state state,
const char *device_address)
- AudioSystem::stream_type 音频流的类型,一共有10种类型;AudioSystem::audio_devices 音频输入输出设备,xml 文件中可配置;
AudioPolicyManager::routing_strategy 音频路由策略,可以有4种策略;
参考链接 https://blog.csdn.net/u012188065/article/details/84104275 https://blog.csdn.net/qq_27136111/article/details/97246184 此篇博文属于精品,音频系统认证全面、准确。 https://blog.csdn.net/droidphone/article/details/5949280
2.4> SoundTringer
@frameworks/av/services/soundtriger/SoundTriggerHwService.cpp 此模块是音频动态管理服务,本地音频设备动态调整时将阐述 uevent 事件,程序根据音频设备变化自动改变音频路由策略。
virtual int loadSoundModel(struct sound_trigger_sound_model *sound_model,
sound_model_callback_t callback,
void *cookie,
sound_model_handle_t *handle);
virtual int unloadSoundModel(sound_model_handle_t handle);
void convertTriggerPhraseToHal(
ISoundTriggerHw::Phrase *halTriggerPhrase,
const struct sound_trigger_phrase *triggerPhrase);
ISoundTriggerHw::SoundModel *convertSoundModelToHal(
const struct sound_trigger_sound_model *soundModel);
三、audio HAL 硬件抽象层接口
3.1> Android 对 Audio HAL 的框架定义
rk3288 实现的 tinyalsa 接口实例代码如下: @ hardware/rockchip/audio/tinyalsa_hal/aduio_hw.cpp
#define LOG_TAG "AudioHardwareTiny"
#include "alsa_audio.h"
#include "audio_hw.h"
#include "audio_hw_hdmi.h"
#include <system/audio.h>
#include "codec_config/config.h"
#include "audio_bitstream.h"
#include "audio_setting.h"
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#ifdef ALSA_IN_DEBUG
FILE *in_debug;
#endif
int get_output_device_id(audio_devices_t device)
{
if (device == AUDIO_DEVICE_NONE)
return OUT_DEVICE_NONE;
if (popcount(device) == 2) {
if ((device == (AUDIO_DEVICE_OUT_SPEAKER |
AUDIO_DEVICE_OUT_WIRED_HEADSET)) ||
(device == (AUDIO_DEVICE_OUT_SPEAKER |
AUDIO_DEVICE_OUT_WIRED_HEADPHONE)))
return OUT_DEVICE_SPEAKER_AND_HEADSET;
else
return OUT_DEVICE_NONE;
}
if (popcount(device) != 1)
return OUT_DEVICE_NONE;
switch (device) {
case AUDIO_DEVICE_OUT_SPEAKER:
return OUT_DEVICE_SPEAKER;
case AUDIO_DEVICE_OUT_WIRED_HEADSET:
return OUT_DEVICE_HEADSET;
case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
return OUT_DEVICE_HEADPHONES;
case AUDIO_DEVICE_OUT_BLUETOOTH_SCO:
case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
return OUT_DEVICE_BT_SCO;
default:
return OUT_DEVICE_NONE;
}
}
int get_input_source_id(audio_source_t source)
{
switch (source) {
case AUDIO_SOURCE_DEFAULT:
return IN_SOURCE_NONE;
case AUDIO_SOURCE_MIC:
return IN_SOURCE_MIC;
case AUDIO_SOURCE_CAMCORDER:
return IN_SOURCE_CAMCORDER;
case AUDIO_SOURCE_VOICE_RECOGNITION:
return IN_SOURCE_VOICE_RECOGNITION;
case AUDIO_SOURCE_VOICE_COMMUNICATION:
return IN_SOURCE_VOICE_COMMUNICATION;
default:
return IN_SOURCE_NONE;
}
}
...
static int adev_open(const hw_module_t* module, const char* name,
hw_device_t** device)
{
struct audio_device *adev;
int ret;
ALOGD(AUDIO_HAL_VERSION);
if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
return -EINVAL;
adev = calloc(1, sizeof(struct audio_device));
if (!adev)
return -ENOMEM;
adev->hw_device.common.tag = HARDWARE_DEVICE_TAG;
adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
adev->hw_device.common.module = (struct hw_module_t *) module;
adev->hw_device.common.close = adev_close;
adev->hw_device.init_check = adev_init_check;
adev->hw_device.set_voice_volume = adev_set_voice_volume;
adev->hw_device.set_master_volume = adev_set_master_volume;
adev->hw_device.set_mode = adev_set_mode;
adev->hw_device.set_mic_mute = adev_set_mic_mute;
adev->hw_device.get_mic_mute = adev_get_mic_mute;
adev->hw_device.set_parameters = adev_set_parameters;
adev->hw_device.get_parameters = adev_get_parameters;
adev->hw_device.get_input_buffer_size = adev_get_input_buffer_size;
adev->hw_device.open_output_stream = adev_open_output_stream;
adev->hw_device.close_output_stream = adev_close_output_stream;
adev->hw_device.open_input_stream = adev_open_input_stream;
adev->hw_device.close_input_stream = adev_close_input_stream;
adev->hw_device.dump = adev_dump;
route_init();
adev->input_source = AUDIO_SOURCE_DEFAULT;
adev->hdmi_drv_fd = -1;
#ifdef AUDIO_3A
adev->voice_api = NULL;
#endif
*device = &adev->hw_device.common;
for(int i =0; i < OUTPUT_TOTAL; i++){
adev->outputs[i] = NULL;
}
char value[PROPERTY_VALUE_MAX];
if (property_get("audio_hal.period_size", value, NULL) > 0) {
pcm_config.period_size = atoi(value);
pcm_config_in.period_size = pcm_config.period_size;
}
if (property_get("audio_hal.in_period_size", value, NULL) > 0)
pcm_config_in.period_size = atoi(value);
read_snd_card_info();
return 0;
}
static struct hw_module_methods_t hal_module_methods = {
.open = adev_open,
};
struct audio_module HAL_MODULE_INFO_SYM = {
.common = {
.tag = HARDWARE_MODULE_TAG,
.module_api_version = AUDIO_MODULE_API_VERSION_0_1,
.hal_api_version = HARDWARE_HAL_API_VERSION,
.id = AUDIO_HARDWARE_MODULE_ID,
.name = "Manta audio HW HAL",
.author = "The Android Open Source Project",
.methods = &hal_module_methods,
},
};
此代码是 rockchip 实现 tinyalsa_hal 源码,此库会在 AudioPolicyManager.cpp 源码中调用并装载至 AudioFlinger 封装对象中。
3.2> Linux tinyalsa 库部分
extern/tinyalsa/README.MD tinyalsa: a small library to interface with ALSA in the Linux kernel
此部分通过源码 mixer.c与pcm.c 产生 libtinyalsa.so 库文件,在 tinyalsa_hal 中调用此库,来管理 linux 内核中声卡。 在此查看库接口,就能够分析处库提供功能及多声卡切换相关逻辑。
The aims are:
- Provide a basic pcm and mixer API
- If it’s not absolutely needed, don’t add it to the API
- Avoid supporting complex and unnecessary operations that could be
dealt with at a higher level
参考链接: Android音频框架笔记 - 上篇 概述:此片记录 android 源码中 看声卡提供服务接口、JNI内容,比较优秀文章。 https://www.jianshu.com/p/9481b1482367
|