通过本文可了解Android系统的音频架构,基本组件及功能,大概了解常用的播放模式,音频流传输路径,低延迟音频的一些能力,AudioServer服务的初始化。本文仅供交流学习。
1 Android音频系统架构
1.1 Audio Framework架构
Audio系统的核心实现均在native c++层,提供java/C++ API供应用使用Audio部分能力,通过hal隔离硬件差异。
Android Audio Framework系统架构
1.2 车载音频路由架构
google提供的车载音频路由
1.3 音频数据传输路径
音频数据传输路径
2 属性定义
2.1 AudioAttribute
音频系统使用该属性进行音频焦点控制、音频通道路由及音量控制等,一般在应用开发中常用。
AudioAttributes {
mUsage //指定为什么要播放该声音,该声音的作用是什么。用来控制焦点、路由及音量决策(USAGE_MEDIA、 USAGE_VOICE_COMMUNICATION、未知等)
mContentType //指定播放来源的类型(CONTENT_TYPE_MOVIE、CONTENT_TYPE_MUSIC、语音、发音、未知等)
mSource
mFlags //指定音频框架如何对音频播放应用效果
mTags / mFormattedTags / mBundle (key value pairs)
}
2.2 DeviceType
系统音频设备类型主要用于区分系统支持的录音及播音设备能力,一般在audio hal开发中常用。Android系统定义的设备类型如下(定义audio-base.h里):
设备类型 | 描述 |
---|---|
AUDIO_DEVICE_OUT_BUS | 输出设备,Android 的主要输出(车载应用下Android 的所有音频均通过这种方式) |
AUDIO_DEVICE_OUT_TELEPHONY_TX | 输出设备,电话下行数据(车载相关) |
AUDIO_DEVICE_OUT_EARPIECE | 输出设备,听筒(手机) |
AUDIO_DEVICE_OUT_SPEAKER | 输出设备,扬声器(手机) |
AUDIO_DEVICE_IN_BUS | 输入设备,基本的录音设备(车载相关) |
AUDIO_DEVICE_IN_FM_TUNER | 输入设备,收音机的输入(车载相关) |
AUDIO_DEVICE_IN_LINE | 输入设备,AUX IN音频(车载相关) |
AUDIO_DEVICE_IN_BLUETOOTH_A2DP | 输入设备,通过蓝牙接收到的音乐(车载相关) |
AUDIO_DEVICE_IN_TELEPHONY_RX | 输入设备,电话上行数据 |
3.关键组件
3.1 AudioPolicy
负责音频路由,音频录音或播音设备的选择。是运行在audioserver 进程中一个服务。在手机场景负责插上耳机的音频通道切换,车载场景负责音频的路由即选择何种音源在哪个设备播放。
3.2 AudioFlinger
是Audio数据消费者,消费音频数据并推进Audio hal、并与Audio Hal对接完成一些控制操作。也是运行在audioserver 进程中一个服务。内部涉及的关键模块:
- Tracks.cpp:音频流管理,可控制音频流的状态,如 start、stop、pause
- Threads.cpp:回放线程和录制线程;回放线程从 FIFO 读取回放数据并混音处理,然后写数据到输出流设备;录制线程从输入流设备读取录音数据并重采样处理,然后写数据到 FIFO。
- AudioMixer.cpp:混音处理,包括重采样、音量调节、声道转换等,其中的重采样复用了 AudioResampler;由playback线程 AudioFlinger::MixerThread 直接使用
- AudioResampler.cpp:重采样处理,可进行采样率转换和声道转换;由录制线程 AudioFlinger::RecordThread 直接使用
- Effects.cpp:音效处理
3.3 AudioTrack
Audio数据生产者,用于向音频输出设备发送音频数据数,播放的数据为 PCM 格式音频数据,每一个音频流对应着一个AudioTrack类的一个实例,每个AudioTrack会在创建时注册到 AudioFlinger中,由AudioFlinger把所有的AudioTrack进行混合,然后输送到Audio HAL中进行播放。
目前Android11同时最多可以创建128个音频流。
4 播放模式
Android目前支持3种播放模式,最常用的是deep buffer模式。具体采用那种播放模式,是在audioPolicy中根据音频流属性AudioAttribute进行控制的。
4.1 Deep buffer playback
Android开发中最常用的播放模式,音乐等对时延要求不高的声音输出采用该模式。边加载边播放,由CPU进行解码,再送入AudioFlinger进行混音播放。处理流程如下:
- MediaPlayer将压缩的音频文件通过MediaCodec解成PCM数据。
- MediaPlayer通过AudioSink将数据搬运到AudioFlinger。
- AudioFlinger做混音及音效处理(audio系统中支持的音效有均衡器、低音增强、环绕声等)。
- AudioFlinger将处理好的数据从用户空间(匿名共享内存)拷贝到内核空间(DMA缓冲区)。
- DMA控制器将内核空间数据拷贝到对应后端设备。
4.2 Low latency playback
低延迟播放模式,用于按键音、游戏背景音等对时延要求高场景。一次加载完数据,应用一般采用soundpool播放。处理流程如下:
- 初试化时就由SoundPool加载压缩文件。
- 通过MediaPlayerService将音频文件解成PCM数据
- 由SoundPool送给AudioFlinger。
4.3 Compressed offload playback
也是用于音乐播放,但将音频解码的部分放在aDSP进行解码,混音及音效处理,这样可以降低CPU的负载,目前支持的格式有MP3/AAC。处理流程如下:
- MediaPlayer不进行音乐文件解码,直接将音频数据转成字节流通过AudioTrack送给AudioFlinger。
- AudioFlinger内部通过OffloadThread 将音频数据从用户空间(匿名共享内存)拷贝到内核空间。
- aDSP内部接收到数据采用MP3/AAC decoder进行解码工作。
- 解码完成,aDSP将音频数据送入内部的Mixer进行混音。
- 混音完成送入DMA缓冲区。
- DMA控制器将DMA缓冲区拷贝到对应后端设备。
5 低延迟音频
5.1 AAudio
Android提供AAudio进行低延迟音频的开发,通过mmap的方式进行音频数据的传输,对比普通的匿名共享内存+内核缓冲区的方式减少一次内存拷贝。AAudio也提供两种工作模式:
EXCLUSIVE mode
该模式下,应用可直接通过mmap的地址空间,将音频数据写入驱动。
SHARED mode
该模式下,应用需通过AudioServer对接mmap的地址空间,将音频数据写入驱动。但AudioServer不会对音频数据进行混音,音效处理等,因此延迟也会大大减少。
5.2 OpenSL ES
Open Sound Library for Embedded Systems,Android NDK 提供的OpenSL ES API 接口,它支持在 native 层直接处理音频数据,因此可减少java与native之间的数据拷贝工作。
6 Audio服务的初始化
6.1 audioserver deamon进程启动
通过init进程fork出来audioserver进程。
//frameworks/av/media/audioserver/audioserver.rc
service audioserver /system/bin/audioserver
class core
user audioserver
onrestart restart audio-hal-2-0
ioprio rt 4 //设置io优先级
disabled
main_audioserver的main函数被调用,进行AudioFlinger 及 AudioPolicyService服务的启动及初始化。
//frameworks\av\media\audioserver\main_audioserver.cpp
int main(int argc __unused, char **argv)
{
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
ALOGI("ServiceManager: %p", sm.get());
//1.初始化AudioFlinger
AudioFlinger::instantiate();
//2.初始化AudioPolicyService
AudioPolicyService::instantiate();
}
6.2 启动AudioFlinger子服务
AudioFlinger服务继承自BinderService,BnAudioFlinger。
instantiate是BinderService里实现的通用方法,会创建对应AudioFlinger服务, 并加入ServiceManager中。
// frameworks\native\libs\binder\include\binder\BinderService.h
static status_t publish(
bool allowIsolated = false,
int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT) {
sp<IServiceManager> sm(defaultServiceManager());
//创建AudioFlinger服务并加入ServiceManager中
return sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated,
dumpFlags);
}
static void instantiate() { publish(); }
AudioFlinger构造函数如下:
主要进行与audio hal及音效hal服务的绑定。
// frameworks/av/services/audioflinger/AudioFlinger.cpp
AudioFlinger::AudioFlinger()
: BnAudioFlinger(),.....{
// 创建mDevicesFactoryHal示例,与audio hal服务绑定。
mDevicesFactoryHal = DevicesFactoryHalInterface::create();
mEffectsFactoryHal = EffectsFactoryHalInterface::create();
}
audioflinger继承自Refbase,因此也会执行onFirstRef()函数,不过google已经将重要的初始化逻辑迁移进了构造函数执行了。
6.3 启动AudioPolicyService子服务
AudioPolicyService初始化的重要逻辑在其onFirstRef()中实现。
//frameworks/av/services/audiopolicy/service/AudioPolicyService.cpp
void AudioPolicyService::onFirstRef()
{
{
Mutex::Autolock _l(mLock);
// start audio commands thread
mAudioCommandThread = new AudioCommandThread(String8("ApmAudio"), this);
// start output activity command thread
mOutputCommandThread = new AudioCommandThread(String8("ApmOutput"), this);
// 创建AudioPolicyManager,policy中大部分核心工作均在AudioPolicyManager中实现
mAudioPolicyClient = new AudioPolicyClient(this);
mAudioPolicyManager = createAudioPolicyManager(mAudioPolicyClient);
}
// load audio processing modules
sp<AudioPolicyEffects>audioPolicyEffects = new AudioPolicyEffects();
{
Mutex::Autolock _l(mLock);
mAudioPolicyEffects = audioPolicyEffects;
}
mUidPolicy = new UidPolicy(this);
mUidPolicy->registerSelf();
mSensorPrivacyPolicy = new SensorPrivacyPolicy(this);
mSensorPrivacyPolicy->registerSelf();
}
关联文章