基于Android P版本分析
Audio简介
Audio系统是Android中负责音频方面的数据流传输和控制的,也负责音频设备的管理。
架构图
从层级上看,Audio的架构层次和其他的模块的架构基本类同,都分为了4个层次:Application、Framework、Native、HAL层;
Application:
上层应用,包括各种音乐播放器、语音播报扥个声音输出软件。
Framework:
提供Application层用于定义开发的Audio接口以及对应的JNI层的接口;
我们常见的使用方式为MediaRecorder/MediaPlayer和AudioRecord/AudioTrack用于录制(采集)和播放音频文件或者是音频流数据;
工具类 | 描述 |
---|---|
MediaRecorder | 录制生成的是音频文件,即继承了录制、编码、压缩等功能,生成的文件支持常见的播放器播放 |
AudioRecord | 录制生成的是PCM音频数据,即音频的原始数据,对应的生成的PCM音频文件不能直接使用播放器播放,而需要适应对应AudioTrack进行读取播放 |
MediaPlayer | 可以支持多种音频文件格式的播放,例如MP3、AAC、WAV、OGG等一些常见的音频格式 |
AudioTrack | 只支持PCM音频数据的读取,然后使用AudioFlinger进行混音,然后通过硬件设备播放 |
其中MediaRecorder和MediaPlayer分别集成了AudioRecord和AudioTrack,同时还集成了AudioRecord和AudioTrack所不支持的MediaCodec,用于编解码音视频数据;
其中还有一些AudioManager、AudioSystem、AudioService,用于提供声音控制、音效设置、通道选择等功能;
上述描述的是Framework Java层的API接口分析,JNI层会有对应的JNI的实现,用于连接Native层对应的类;
Native:
在Native层,一般情况下,Android中的大多数模块都会划分为两个部分:客户端和服务端,客户端用于和JNI层进行通信,服务端用于执行client层传入的请求或者是命令等;
-
client:
AudioTrack、AudioRecord、MediaPlayer、MediaRecorder、AudioSystem对应Java层的实现类。
-
server:
在client和server中,其实还有一块,就是Binder IPC Proxies,其中定义了IAudioTrack.cpp、IAudioRecord.cpp、IAudioFlinger.cpp等,用于client和server进行通信;
在server中包含了最核心的AudioPolicyService和AudioFlinger,其中AudioPolicyService是Audio系统策略的制定者,掌管系统中声音设备的选择和切换、音量控制等功能;而AudioFlinger为Audio系统策略的执行者,即工作引擎,管理着系统中的输入输出音频流,承担音频数据的混音以及读写Audio硬件等工作;
HAL:
HAL层是AudioFlinger向下访问的对象,该层一般厂商会实现自己的接口层,桥接硬件驱动和上层框架;
Android Audio上层设计框架中与硬件抽象层直接交互的只有AudioFlinger和AudioPolicyService。HAL层的任务就是提供同一的接口来定义它与AudioFlinger/AudioPolicyService之间的通信方式;
Kernel:
一般常见的有ALSA(先进Linux声音架构)、OSS(开放声音系统)以及定制化的Driver,OSS是一个商业声卡驱动程序,需要购买,一般我们使用ALSA驱动程序;
总之,基于上述的描述,汇总了一下;
在 Android Audio 系统设计中,无论是上层还是下层都是用一个管理类和输入输出两个类来表示 Audio 系统,输入输出两个类负责数据通道,在各个层级间对应关系:
Audio管理环节 | Audio输出 | Audio输入 | |
---|---|---|---|
Java层 | android.media.AudioSystem | android.media.AudioTrack | android.media.AudioRecord |
本地框架层 | AudioSystem | AudioTrack | AudioRecord |
AudioFlinger | IAudioFlinger | IAudioTrack | IAudioRecord |
硬件抽象层 | AudioHardwareInterface | AudioStreamOut | AudioStreamIn |
各层级之间的调用关系:
Java Audio
在Java层,Audio提供了3个类,分别对应了3类功能:
- AudioService.java:负责的是Audio系统的综合管理功能,包括音量控制,音频IO设备的管理、音频焦点机制;
- AudioTrack.java:负责PCM音频数据的输出,通过向FIFO环形缓冲区中写入PCM音频数据供AudioFlinger使用;
- AudioRecord.java:负责PCM音频数据的采集,通过从FIFO环形缓冲区中读取MIC采集的数据;
AudioService
AudioService由SystemServer启动,实现了IAudioService的Bn端,AudioManager实现了IAudioService的Bp端;
AudioService的功能实现依赖Java AudioSystem类,AudioSystem.java是Native AudioSystem在Java层的封装和代理;
AudioTrack
AudioTrack通过JNI的方式使用android_media_AudioTrack.cpp封装的接口,进而使用到Native AudioTrack提供的接口;
AudioRecord
AudioRecord通过JNI的方式使用android_media_AudioRecord.cpp封装的接口,进而使用到Native AudioRecord提供的接口;
Native Audio
Native Audio服务在Android N之前存在于mediaserver中,Android N之后有audioservice来启动,在init进程中通过加载audioservice.rc来启动audioserver;
audioServer主要启动了两个Native Binder服务:
- AudioFlinger:音频系统策略的执行者, 负责音频流设备的管理及音频流数据的处理传输, 由libaudioflinger实现具体功能
- AudioPolicyService:音频系统策略的制定者, 负责音频设备切换的策略抉择、音量调节策略等, 由libaudiopolicyservice实现具体功能
AudioFlinger
AudioFlinger实现了名为media.audio_flinger的BnAudioFlinger,而BpAudioFlinger由libaudioclient的IAudioFlinger实现;
// 实现 BnAudioFlinger
libaudioflinger <==> frameworks/av/services/audioflinger/*
// 实现 BpAudioFlinger
libaudioclient <==> frameworks/av/media/libaudioclient/*
在AudioFlinger中,将DeviceHalInterface抽象为AudioHwDevice(音频硬件设备)和AudioStreamOut(音频输出流)。AudioFlinger通过对DeviceHalInterface对象对音频输出流以及对应的device进行操作;
AudioPolicyService
同理,AudioPolicyService和AudioFlinger类似,同样是实现了名为media.audio_policy的BnAudioPolicyService,而BpAudioPolicyService由libaudioclient的IAudioPolicyService实现;
// 实现 BnAudioPolicyService
libaudiopolicyservice <==> frameworks/av/services/audiopolicy/*
// 实现 BpAudioPolicyService
libaudioclient <==> frameworks/av/media/libaudioclient/*
与AudioPolicyService对应的还有一个AudioPolicyManager,在APS中通过mpPolicyManager对象调用APM中的逻辑,APM通过其中的mpClientInterface对象访问APS。其中mpClientInterface对象类型为AudioPolicyClientInterface,APS继承了AudioPolicyClientInterface;
其中,APS很大一部分工作都是在APM中实现完成的;
APM其中包含两个变量:mAvailableOutputDevice和mAvailableInputDevice:
- mAvailableOutputDevice:可用输出设备集合
- mAvailableInputDevice:可用输入设备集合
libaudioclient
libaudioclient实现了AudioFlinger和AudioPolicyService的BpXxxx,并实现了media JNI:
// android::media::* <===> frameworks/av/media/libaudioclient/
// JNI <===> frameworks/base/core/jni
-----------------------------------------------------
| android::media::* | JNI |
-----------------------------------------------------
| AudioSystem.cpp | android_media_AudioSystem.cpp |
| AudioRecord.cpp | android_media_AudioRecord.cpp |
| AudioTrack.cpp | android_media_AudioTrack.cpp |
-----------------------------------------------------
通过上述的一系列分析,我们可以看出,libaudioclient在native层的角色可以通过命名直观的看出,作为native层的client,主要是用于和Java层进行交互,libaudioclient作为一个中间件,连接起了Java层和Native层service端的通信;
Audio HAL
上层所有的逻辑,最终都会流转到HAL层,通过AF与HAL进行通信。
Audio HAL架构比较复杂,混合了HIDL和Legacy HAL,对于厂商来说,实现以so库的方式音频接口,并在音频策略配置文件(audio_policy_configuration.xml)中进行配置,系统就会在启动时自动加载对应的音频设备;
audio.h及其扩展
HAL接口定义在/hardware/libhardware/include/hardware/audio.h文件中,其中包括了下面几个结构体定义;
- audio_hw_device:音频设备,可以理解为一个声卡,它使用audio_stream_out结构来表示输出,使用audio_stream_in来表示输入
- audio_stream_out:输出流,其中包括了write()
- audio_stream_in:输入流,其中包括了read()
- audio_stream:音频流
下面是当期那已经实现或参考的音频设备(实现或者是扩充了上述audio.h):
- 默认主设备:/hardware/libhardware/modules/audio
- 车载主设备:/device/generic/car/emulator/audio/driver
- USB设备:/hardware/libhardware/modules/usbaudio
- RemoteSubmix设备:/hardware/libhardware/modules/audio_remote_submix
- 蓝牙A2DP设备:/system/bt/audio_a2dp_hw
HAL接口
Audio HAL接口(以4.0为例)是对音频接口的进一步抽象;
IDevice.hal
函数名 | 描述 |
---|---|
initCheck() | 检测硬件是否初始化完毕 |
setMasterVolume(float) | 设置除voice call外其他音频活动的音量 |
getMasterVolume() | 获取主音量 |
setMicMute(bool) | 设置MIC的静音状态 |
getMicMute() | 获取MIC的静音状态 |
setMasterMute(bool) | 设置静音状态 |
getMasterMute() | 获取静音状态 |
getInputBufferSize(AudioConfig) | 获取输入缓冲区的大小 |
openOutputStream(*) | 创建和开启音频硬件输出流 |
openInputStream(*) | 创建和开启音频硬件输入流 |
supportsAudioPatches() | 判断HAL是否支持音频路由 |
createAudioPatch(*) | 为SRC和SINK创建音频路由 |
releaseAudioPatch(*) | 释放音频路由 |
getAudioPort(*) | 获取指定的音频端口属性 |
setAudioPortConfig(*) | 设置指定音频端口的配置 |
getHwAvSync() | 获取设备的硬件同步源 |
setScreenState(bool) | 设置屏幕状态 |
getParameters(vec) | 获取厂商定义的参数值 |
setParameters(vec) | 设置厂商定义的参数值 |
getMicrophones() | 返回设备中麦克风的数组 |
setConnectedState(*) | 通知设备模块附加到它的输入/输出设备的连接状态 |
IPrimaryDevice.hal
函数名 | 描述 |
---|---|
setVoiceVolume(float) | 设置voice call音量 |
setMode(AudioMode) | 设置音频模式 |
getBtScoNrecEnabled() | 获取蓝牙ECNR使能状态 |
setBtScoNrecEnabled(bool) | 设置蓝牙ECNR使能状态 |
getBtScoWidebandEnabled() | 获取蓝牙Wideband使能状态 |
setBtScoWidebandEnabled(bool) | 设置蓝牙Wideband使能状态 |
getBtHfpEnabled() | 获取蓝牙HFP使能状态 |
setBtHfpEnabled(bool) | 设置蓝牙HFP使能状态 |
setBtHfpSampleRate(uint32_t) | 设置蓝牙HFP的当前采样率 |
setBtHfpVolume(float) | 设置蓝牙HFP的当前输出音量 |
getTtyMode() | 获取当前TTY模式 |
setTtyMode() | 设置当前TTY模式 |
getHacEnabled() | 获取HearingAid使能状态 |
setHacEnabled() | 设置HearingAid使能状态 |
IDevicesFactory.hal
函数名 | 描述 |
---|---|
openDevice(string device) | 开启设备 |
openPrimaryDevice() | 开启主设备 |
IStream.hal
函数名 | 描述 |
---|---|
getFrameSize() | 获取帧大小 |
getFrameCount() | 获取缓冲区帧数 |
getBufferSize() | 获取流的缓冲区大小 |
getSampleRate() | 获取采样率 |
setSampleRate(uint32_t) | 设置采样率 |
getChannelMask() | 获取流的channel mask |
getSupportedChannelMasks(AudioFormat) | 获取流支持的channel mask |
setChannelMask(bitfield) | 设置流的channel mask |
getFormat() | 获取流的音频格式 |
getSupportedFormats() | 获取流支持的音频格式 |
setFormat(AudioFormat) | 设置流的音频格式 |
getAudioProperties() | 获取音频流参数 |
addEffect(uint64_t) | 新增音效到流 |
removeEffect(uint64_t) | 停止流上的音效 |
standby() | 让硬件输入输出进入standby模式 |
getDevices() | 获取流连接的设备 |
setDevices(vec) | 连接设置到流 |
setHwAvSync(AudioHwSync) | 设置硬件同步源 |
getParameters(vec, vec) | 获取厂商参数 |
setParameters(vec, vec) | 设置厂商参数 |
start() | 开始流操作 |
stop() | 停止流操作 |
createMmapBuffer(int32_t) | 创建audio mmap缓冲区 |
getMmapPosition() | 获取audio mmap缓冲区的读写指针位置 |
close() | 关闭流操作 |
IStreamIn.hal
函数名 | 描述 |
---|---|
getAudioSource() | 获取输入流的source描述 |
setGain(float) | 设置音频驱动的输入增益 |
updateSinkMetadata(SinkMetadata) | 当流的接收的元数据被更改时调用 |
prepareForReading(uint32_t, uint32_t) | 设置必需的传输层以从驱动接收音频缓冲区 |
getInputFramesLost() | 获取丢失的输入帧的数量 |
getCapturePosition() | 获取接收到的音频帧数与时钟时间 |
getActiveMicrophones() | 返回设备中可用的麦克风的数组 |
IStreamOut.hal
函数名 | 描述 |
---|---|
getLatency() | 获取硬件传输延迟 |
setVolume(float left, float right) | 设置音量,用于混音后 |
updateSourceMetadata(SourceMetadata sourceMetadata) | 当流源的元数据被更改时调用 |
prepareForWriting(uint32_t frameSize, uint32_t framesCount) | 设置必需的传输层将音频缓冲区传递给驱动 |
getRenderPosition() | 获取音频DSP写入DAC的音频帧数 |
getNextWriteTimestamp() | 获取下一次写入音频驱动时间(微秒) |
setCallback(IStreamOutCallback callback) | 设置回调接口, 用于非阻塞模式 |
clearCallback() | 清空回调 |
supportsPauseAndResume() | 判断HAL是否支持暂停和恢复流 |
pause() | 暂停流 |
resume() | 恢复流 |
supportsDrain() | 判断HAL是否支持引流 |
drain(AudioDrain type) | 引流 |
flush() | 刷新流 |
getPresentationPosition() | 获取音频帧数 |
IStreamOutCallback.hal
函数名 | 描述 |
---|---|
onWriteReady() | 非阻塞写入已完成 |
onDrainReady() | Drain完成 |
onError() | 异常 |
libaudiohal
libaudiohal封装了audio hal的接口,以libaudiohal.so的形式供AudioFlinger使用,而libaudiohal又使用了libaudiohal@4.0和libaudiohal@2.0两个库,同时libaudiohal@4.0和libaudiohal@2.0又分别是audio hal接口的封装;
libaudiohal最终提供的是DeviceHalInterface、DevicesFactoryHalInterface、EffectsFactoryHalInterface接口;
总结
上述按照Java、Native、HAL的形式,分层次描述了Audio架构的关系:
AudioFlinger
我们看一下AudioFlinger,AudioTrack和AudioFlinger具有强关联性,AudioTrack读取了PCM数据流之后,这个数据流之后的流转必须经过AudioFlinger,因为AudioFlinger是音频策略的执行者,负责音频流设备的管理和音频流数据的处理传输;
代码文件结构
我们首先看一下AudioFlinger中代码文件结构:
av/services/audioflinger/
├── Android.mk
├── AudioFlinger.cpp
├── AudioFlinger.h
├── AudioHwDevice.cpp
├── AudioHwDevice.h
├── AudioStreamOut.cpp
├── AudioStreamOut.h
├── AudioWatchdog.cpp
├── AudioWatchdog.h
├── AutoPark.h
├── BufLog.cpp
├── BufLog.h
├── Configuration.h
├── Effects.cpp
├── Effects.h
├── FastCapture.cpp
├── FastCaptureDumpState.cpp
├── FastCaptureDumpState.h
├── FastCapture.h
├── FastCaptureState.cpp
├── FastCaptureState.h
├── FastMixer.cpp
├── FastMixerDumpState.cpp
├── FastMixerDumpState.h
├── FastMixer.h
├── FastMixerState.cpp
├── FastMixerState.h
├── FastThread.cpp
├── FastThreadDumpState.cpp
├── FastThreadDumpState.h
├── FastThread.h
├── FastThreadState.cpp
├── FastThreadState.h
├── MmapTracks.h
├── MODULE_LICENSE_APACHE2
├── NOTICE
├── OWNERS
├── PatchPanel.cpp
├── PatchPanel.h
├── PlaybackTracks.h
├── RecordTracks.h
├── ServiceUtilities.cpp
├── ServiceUtilities.h
├── SpdifStreamOut.cpp
├── SpdifStreamOut.h
├── StateQueue.cpp
├── StateQueue.h
├── StateQueueInstantiations.cpp
├── Threads.cpp
├── Threads.h
├── TrackBase.h
├── Tracks.cpp
├── TypedLogger.cpp
└── TypedLogger.h
0 directories, 54 files
其中包括 Threads.cpp、Tracks.cpp、Effects.cpp、PatchPanel.cpp、FastThread.cpp、FastMixer.cpp等功能对应的cpp文件,同时还有一些功能对应的文件,例如AudioMixer.cpp、AudioResampler.cpp放置到了别的位置,重新生成了一个包;
我们针对几个cpp文件进行简单的描述:
- AudioResampler.cpp:重采样处理类,可进行采样率转换和声道转换,由录制线程AudioFlinger::RecordThread直接使用;
- AudioMixer.cpp:混音处理类,包括重采样、音量调节、声道转换等,其中的重采样复用了AuidoResampler,由回放线程AudioFlinger::MixerThread直接使用;
- Effects.cpp:音效处理类;
- Tracks.cpp:音频流管理类,可控制音频流的装填,如start、stop、pause等;
- Threads.cpp:回放线程和录制线程类,回放线程从FIFO读取回访数据并混音处理,然后写数据到输出流设备;录制线程从输入流设备读取音频数据并进行重采样处理,然后将数据填充到FIFO中;
- AudioFlinger.cpp:AudioFlinger对外提供的服务接口;
AudioFlinger API
interface | Description |
---|---|
dump | 用于获取Audio 当前的信息,包括audio data、audio OutputThread、sample rate等信息 |
createTrack | 创建对应Java层AudioTrack的Track,这个Track定义在AudioFlinger::PlaybackThread::Track,新建输出流管理对象,找到对应的播放线程,创建Track并返回track代理对象的TrackHandle |
createRecord | 创建对应Java层AudioRecord的Record,这个Track定义在AudioFlinger::PlaybackThread::Record |
sampleRate | 获取硬件设备的采样率 |
format | 获取硬件设备的音频格式 |
frameCount | 获取硬件设备的周期帧数 |
frameCountHAL | 获取HAL层硬件设备的周期帧数 |
latency | 获取硬件设备的传输延迟 |
setMasterVolume | 调节主输出设备的音量 |
setMasterMute | 主输出设备静音 |
masterVolume | 获取主输出设备的音量 |
masterMute | 获取主输出设备静音状态 |
setStreamVolume | 调节指定流类型的音量 |
setStreamMute | 指定流静音 |
streamVolume | 获取指定类型的音频流的音量 |
streamMute | 获取指定类型的音频流的静音状态 |
setMode | 切换模式,normal、ringtone、call、communication |
setMicMute | 静音mic输入 |
getMicMute | 获取mic输入的静音状态 |
setRecordSilenced | 设置输入流静音 |
setParameters | 设置音频参数,调用hal接口,切换通道用的比较多 |
getParameters | 获取音频参数 |
getInputBufferSize | 获取输入缓冲区大小 |
openOutput | 打开输出流设备,并创建PlaybackThread对象 |
closeOutput | 关闭输出流设备,并销毁PlaybackThread上所有track,退出PlaybackThread |
suspendOutput | 暂停输出流 |
restoreOutput | 恢复输出流 |
openInput | 打开输入流设备,并创建RecordThread对象 |
closeInput | 关闭输入流设备 |
setVoiceVolume | 调节通话音量 |
getRenderPosition | 获取音频DSP写入DAC的音频帧数 |
getInputFramesLost | 获取丢失的输入帧的数量 |
根据上述的接口描述,我们大致可以归纳出AudioFlinger响应的服务请求主要有:
- 获取硬件设备的配置信息
- 音量调节
- 静音操作
- 音频模式切换
- 音频参数设置
- 输入输出流设备管理
- 音频流管理
AudioFlinger PlaybackThread
在之前的分析中,我们知道,在创建AudioFlinger的时候,会根据audio output flag创建对应的PlaybackThread:
sp<AudioFlinger::ThreadBase> AudioFlinger::openOutput_l(audio_module_handle_t module,
audio_io_handle_t *output,
audio_config_t *config,
audio_devices_t devices,
const String8& address,
audio_output_flags_t flags)
{
// findSuitableHwDev_l()函数中获取的AudioHwDevice对象就是我们在之前分析过程中,在加载audio policy过程中加载的module设备
AudioHwDevice *outHwDev = findSuitableHwDev_l(module, devices);
if (outHwDev == NULL) {
return 0;
}
if (*output == AUDIO_IO_HANDLE_NONE) {
*output = nextUniqueId(AUDIO_UNIQUE_ID_USE_OUTPUT);
} else {
// Audio Policy does not currently request a specific output handle.
// If this is ever needed, see openInput_l() for example code.
ALOGE("openOutput_l requested output handle %d is not AUDIO_IO_HANDLE_NONE", *output);
return 0;
}
mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
// FOR TESTING ONLY:
// This if statement allows overriding the audio policy settings
// and forcing a specific format or channel mask to the HAL/Sink device for testing.
if (!(flags & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD | AUDIO_OUTPUT_FLAG_DIRECT))) {
……………………
}
AudioStreamOut *outputStream = NULL;
status_t status = outHwDev->openOutputStream(
&outputStream,
*output,
devices,
flags,
config,
address.string());
mHardwareStatus = AUDIO_HW_IDLE;
if (status == NO_ERROR) {
if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
sp<MmapPlaybackThread> thread =
new MmapPlaybackThread(this, *output, outHwDev, outputStream,
devices, AUDIO_DEVICE_NONE, mSystemReady);
mMmapThreads.add(*output, thread);
ALOGV("openOutput_l() created mmap playback thread: ID %d thread %p",
*output, thread.get());
return thread;
} else {
sp<PlaybackThread> thread;
if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
thread = new OffloadThread(this, outputStream, *output, devices, mSystemReady);
ALOGV("openOutput_l() created offload output: ID %d thread %p",
*output, thread.get());
} else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT)
|| !isValidPcmSinkFormat(config->format)
|| !isValidPcmSinkChannelMask(config->channel_mask)) {
thread = new DirectOutputThread(this, outputStream, *output, devices, mSystemReady);
ALOGV("openOutput_l() created direct output: ID %d thread %p",
*output, thread.get());
} else {
thread = new MixerThread(this, outputStream, *output, devices, mSystemReady);
ALOGV("openOutput_l() created mixer output: ID %d thread %p",
*output, thread.get());
}
mPlaybackThreads.add(*output, thread);
return thread;
}
}
return 0;
}
在AudioFlinger的openOutput_l()函数中,涉及到了4种类型的flag对应的PlaybackThread:
-
MmapThread:MmapThread线程是Android8.0新加入的,用于低延迟的放音和录音,与AAudio有关系,有MmapPlaybackThread和MmapCaptureThread两个子类;
- MmapPlaybackThread:MMAP回放线程类,负责处理标识为AUDIO_OUTPUT_FLAG_MMAP_NOIRQ的音频流;
- MmapCaptureThread:MMAP录像线程类,负责处理标识为AUDIO_INPUT_FLAG_MMAP_NOIRQ的音频流;
-
OffloadThread:硬件回放线程类,由DirectOutputThread派生,负责处理标识为AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD的音频流,这种音频流未经软件解码,需要输出到硬件解码器,由硬件解码器解码为PCM数据;
-
DirectOutputThread:直接回放线程类,由PlaybackThread派生,负责处理标识为AUDIO_OUTPUT_FLAG_DIRECT的音频流,这种音频流数据不需要软件混音,直接输出到音频设备即可;
-
MixerThread:混音回放线程类,由PlaybackThread派生,负责处理标示为AUDIO_OUTPUT_FLAG_PRIMARY、AUDIO_OUTPUT_FLAG_FAST、AUDIO_OUTPUT_FLAG_DEEP_BUFFER的音频流,MixerThread可以把多个音轨的数据混音后在输出;
从上述的描述中,我们可知,这几个PlaybackThread之间的关系:
- ThreadBase:PlaybackThread 和 RecordThread 的基类
- RecordThread:录制线程类,由 ThreadBase 派生
- PlaybackThread:回放线程基类,同由 ThreadBase 派生
AudioFlinger::PlaybackThread::threadLoop
该逻辑定义在Threads.cpp中,由于代码过长,我们直接分析其中的主要逻辑:
processConfigEvents_l
处理配置事件。当有配置改变的事件发生时,需要调用sendConfigEvent_l()来通知PlaybackThread,这样PlaybackThread才能及时处理配置事件。
常见的配置事件是切换音频通路;
检查standby条件
检查此时此刻是否符合standby条件,比如当前并没有ACTIVE状态的Track(mActiveTracks.size() = 0),那么调用threadLoop_standby()关闭音频硬件设备以节省能耗;
prepareTracks_l
准备音频流和混音器,其中主要的逻辑:
- 遍历mActiveTracks,逐个处理mActiveTracks上的Track,检查该Track是否为ACTIVE状态;
- 如果Track设置是ACTIVE状态,则再检查该Track的数据是否准备就绪了;
- 根据音频流的额音量值、格式、声道数、音轨的采样率、硬件设备的采样率,配置好混音器参数;
- 如果Track的状态是PAUSED或STOPPED,则把该Track添加到tracksToRemove向量中;
threadLoop_mix
读取所有置为了ACTIVE状态的音频流数据,混音器开始处理这些数据;
threadLoop_write
把混音器处理后的额数据写到输出流设备;
threadLoop_removeTracks
把tracksToRemove上的所有Track从mActiveTracks中移除出来,这样下一次循环时就不会处理这些Track了;
PlaybackThread实例与输出流设备是一一对应的,比方说OffloadThread只会将音频数据输出到compress_offload设备中,MixerThread(with FastMixer)只会将音频数据输出到low_latency设备中;
从Audio HAL中,我们通常看到如下4种输出流设备,其实对应的就是Native层对应的output flag,分别对应着不同的播放场景:
output Device | Description |
---|---|
primary_out | 主输出流设备,用于铃声类声音输出,对应着标识为AUDIO_OUTPUT_FLAG_PRIMARY的音频流和一个MixerThread回放线程实例 |
low_latency | 低延迟输出流设备,用于按键音、游戏背景音等对时延要求高的声音输出,对应着标识为AUDIO_OUTPUT_FLAG_FAST的音频流和一个MixerThread回放线程实例 |
deep_buffer | 音乐音轨输出流设备,用于音乐等对时延要求不高的数据输出,对应着标识为AUDIO_OUTPUT_FLAG_DEEP_BUFFER的音频流和一个MixerThread回放线程实例 |
compress_offload | 硬件输出流设备,用于需要硬件解码的数据输出,对应着标识为AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD的音频流和一个OffloadThread回放线程实例 |
其中primary_out设备是必须声明支持的,而且系统启动时就已经打开primary_out设备并创建好对应的MixerThread实例,其他类型的输出流设备并非必须声明支持的,主要是看硬件上有无能力;
这里需要阐述一个概念:输出流设备属于逻辑设备,并不是硬件设备。所以即使输出流设备一直保持打开,只要硬件设备不工作,那么就不会影响能耗,只有当PlaybackThread将音频数据写入到输出流设备时才会开启硬件设备;
简单的看一下AudioTrack、PlaybackThread和输出流设备三者的对应关系:
输出流设备决定了它对应的PlaybackThread的类型,只有支持了该类型的输出流设备,该类型的PlaybackThread才有可能被创建;
因为PlaybackThread的创建依赖于output device的存在,如果不存在对应的output device,则不会创建对应的PlaybackThread,也不会存在对应的output flag;
系统启动时,默认打开primary_out、low_latency、deep_buffer这3种输出流设备,并创建对应的MixerThread了,而此时DirectOutputThread与OffloadThread不会被创建,直到标识为AUDIO_OUTPUT_FLAG_DIRECT/AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD的音频流需要输出时,才开始创建DirectOutputThread/OffloadThread 和打开 direct_out/compress_offload 设备;这个逻辑其实对应的就是上述的输出流设备属于逻辑设备,并不是硬件设备;
AudioFlinger音频流管理
我们知道,AudioTrack会把音频流数据填充到对应的FIFO缓冲区中,然后由AudioFlinger读取并交由PlaybackThread进行处理。应用进程和AudioFlinger不属于同一个进程,这就需要AudioFlinger提供音频流管理功能,并提供一套通讯接口可以让应用进程跨进程控制AudioFlinger中的音频流状态。
AudioFlinger的音频流管理由AudioFlinger::PlaybackThread::Track实现,其中AudioFlinger在PlaybackThread中保存AudioTrack对应的Track,Track和AudioTrack是一一对应的关系,一个AudioTrack创建之后,那么AudioFlinger会创建一个Track与之对应;PlaybackThread与AudioTrack/Track是一对多的关系,一个PlaybackThread可以挂着多个Track;
Track的创建:AudioTrack创建后,AudioPolicyManager根据AudioTrack的输出标识和流类型,找到对应的输出流设备和PlaybackThread(如果没有找到对应的PlaybackThread,则系统会打开对应的输出流设备并创建对应的PlaybackThread),然后创建一个Track挂载到PlaybackThread中;
PlaybackThread中有两个变量,用于管理其中的Track:
- mTracks:用于保存该PlaybackThread中所有的Track;
- mActiveTracks:用于存储该PlaybackThread中已开启的Track,即Track的状态设置为了ACTIVE状态,PlaybackThread找到所有的Track,然后把这些Track数据混音后写到输出流设备;
我们从上图可以看到,在AudioTrack与AudioFlinger通信之间,还夹杂着两个类:IAudioTrack和TrackHandle。
- IAudioTrack:AudioTrack和AudioFlinger之间通过AIDL进行通信,所以会存在一个IAudioTrack;
- TrackHandle:AudioFlinger::PlaybackThread::Track用于音频流管理,但是Track不是用于对外的接口,所有创建了TrackHandle,相当于封装了Track,其实现还是调用了Track接口;
音频流控制常见的接口:
- AudioFlinger::PlaybackThread::Track::start:开始播放,把该Track置为ACTIVE状态
- AudioFlinger::PlaybackThread::Track::stop:停止播放,把该Track置为STOPPED状态
- AudioFlinger::PlaybackThread::Track::pause:停止播放,把该Track置为PAUSING状态
这3种常见下,执行完成后,都需要调用AudioFlinger::PlaybackThread::broadcast_l()告知PlaybackThread情况有变;
AudioFlinger::PlaybackThread::threadLoop()得悉情况有变后,调用prepareTracks_l()重新准备音频流和混音器,包括对mActiveTracks集合的更新和AudioMixer的重新准备;
AudioPolicyService
AudioPolicyService和AudioFlinger有强关联性。AudioFlinger的角色为音频策略执行者,执行既定义的音频策略,而AudioPolicyService作为音频策略的定义者,告诉AudioFlinger
AudioPolicyService API
AudioPolicy
AudioStream
AudioPolicy提供了一个音频输入、输出管理的中心,AudioPolicy模块承载着音频切换,音轨路由的重要工作;
AudioPolicyManager在创建的过程中,会通过audio_policy.conf配置文件来加载音频设备,Android为每种音频接口定义了对应的硬件抽象层hardware/libhardware/modules/audio;
external/bluetooth/bluedroid/audio_a2dp_hw/ | audio.a2dp.default.so |
hardware/libhardware/modules/audio/ | audio.primary.default.so |
hardware/libhardware/modules/usbaudio/ | audio.usb.default.so |
每种音频接口定义了不同的输入输出,一个接口可以具有多个输入或者输出,每个输入输出可以支持不同的设备,通过读取audio_policy.conf文件可以获取系统支持的音频接口参数,在AudioPolicyManager中会优先加载/vendor/etc/audio_policy.conf配置文件, 如果该配置文件不存在, 则加载/system/etc/audio_policy.conf配置文件。AudioPolicyManager加载完所有音频接口后,就知道了系统支持的所有音频接口参数,可以为音频输出提供决策。