前言
AudioPolicyService 与 AudioFlinger 是 Android 音频系统的两大基本服务。前者是音频系统策略的制定者,负责音频设备切换的策略抉择、音量调节策略等;后者是音频系统策略的执行者,负责音频流设备的管理及音频流数据的处理传输,所以 AudioFlinger 也被认为是 Android 音频系统的引擎。
AudioFlinger 服务启动
从 Android 7.0 开始,AudioFlinger 在系统启动时由 audioserver 加载(之前版本由 mediaserver 加载),详见 frameworks/av/media/audioserver/main_audioserver.cpp:
int main(int argc, char** argv)
{
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();
}
可见 audioserver 把音频相关的服务都加载了,包括 AudioFlinger、AudioPolicyService、RadioService、SoundTriggerHwService。
AudioFlinger 服务启动后,其他进程可以通过 ServiceManager 来获取其代理对象 IAudioFlinger,通过 IAudioFlinger 可以向 AudioFlinger 发出各种服务请求,从而完成自己的音频业务。
AudioFlinger 服务接口
[-->AudioHardwareInterface.h::AudioHardwareInterface声明]
class AudioHardwareInterface
{
public:
virtual ~AudioHardwareInterface() {}
//用于检查硬件是否初始化成功,返回的错误码定义在include/utils/Errors.h
virtual status_t initCheck() =0;
//设置通话音量,范围从0到1.0
virtual status_t setVoiceVolume(float volume) = 0;
/*
设置除通话音量外的其他所有音频流类型的音量,范围从0到1.0,如果硬件不支持的话,
这个功能会由软件层的混音器完成
*/
virtual status_t setMasterVolume(float volume) = 0;
/*
设置模式,NORMAL的状态为普通模式,RINGTONE表示来电模式(这时听到的声音是来电铃声)
IN_CALL表示通话模式(这时听到的声音是手机通话过程中的语音)
*/
virtual status_t setMode(intmode) = 0;
// 和麦克相关
virtual status_t setMicMute(bool state) = 0;
virtual status_t getMicMute(bool* state) = 0;
// 设置/获取配置参数,采用key/value的组织方式
virtual status_t setParameters(const String8& keyValuePairs) = 0;
virtual String8 getParameters(const String8& keys) = 0;
// 根据传入的参数得到输入缓冲的大小,返回0表示其中某个参数的值Audio HAL不支持
virtualsize_t getInputBufferSize(uint32_tsampleRate, int format, int channelCount) = 0;
/*下面这几个函数非常重要 */
/*
openOutputStream:创建音频输出流对象(相当于打开音频输出设备)
AF可以往其中write数据,指针型参数将返回该音频输出流支持的类型、声道数、采样率等
*/
virtual AudioStreamOut* openOutputStream(
uint32_tdevices,
int *format=0,
uint32_t*channels=0,
uint32_t*sampleRate=0,
status_t*status=0) = 0;
// 关闭音频输出流
virtual void closeOutputStream(AudioStreamOut* out) = 0;
// 创建音频输入流对象(相当于打开音频输入设备),AF可以read数据
virtual AudioStreamIn* openInputStream(
uint32_tdevices,
int *format,
uint32_t*channels,
uint32_t *sampleRate,
status_t*status,
AudioSystem::audio_in_acoustics acoustics) = 0;
virtual void closeInputStream(AudioStreamIn* in) =0;
//关闭音频输入流
virtual status_t dumpState(int fd, const Vector<String16>&args) = 0;
//静态create函数,使用设计模式中的工厂模式,具体返回的对象由厂商根据硬件的情况决定
staticAudioHardwareInterface* create();
......
};
根据上面的代码,可以得出以下结论:
- AudioHardwareInterface管理音频输出设备对象(AudioStreamOut)和音频输入设备对象(AudioStreamIn)的创建。
- 通过AudioHardwareInterface可设置音频系统的一些参数。
AudioFlinger 对外提供的主要的服务接口如下:
Interface | Description |
---|
sampleRate | 获取硬件设备的采样率 | format | 获取硬件设备的音频格式 | frameCount | 获取硬件设备的周期帧数 | latency | 获取硬件设备的传输延迟 | setMasterVolume | 调节主输出设备的音量 | setMasterMute | 静音主输出设备 | setStreamVolume | 调节指定类型的音频流的音量,这种调节不影响其他类型的音频流的音量 | setStreamMute | 静音指定类型的音频流 | setVoiceVolume | 调节通话音量 | setMicMute | 静音麦克风输入 | setMode | 切换音频模式:音频模式有 4 种,分别是 Normal、Ringtone、Call、Communicatoin | setParameters | 设置音频参数:往下调用 HAL 层相应接口,常用于切换音频通道 | getParameters | 获取音频参数:往下调用 HAL 层相应接口 | openOutput | 打开输出流:打开输出流设备,并创建 PlaybackThread 对象 | closeOutput | 关闭输出流:移除并销毁 PlaybackThread 上面挂着的所有的 Track,退出 PlaybackThread,关闭输出流设备 | openInput | 打开输入流:打开输入流设备,并创建 RecordThread 对象 | closeInput | 关闭输入流:退出 RecordThread,关闭输入流设备 | createTrack | 新建输出流管理对象: 找到对应的 PlaybackThread,创建输出流管理对象 Track,然后创建并返回该 Track 的代理对象 TrackHandle | openRecord | 新建输入流管理对象:找到 RecordThread,创建输入流管理对象 RecordTrack,然后创建并返回该 RecordTrack 的代理对象 RecordHandle |
可以归纳出 AudioFlinger 响应的服务请求主要有:
- 获取硬件设备的配置信息
- 音量调节
- 静音操作
- 音频模式切换
- 音频参数设置
- 输入输出流设备管理
- 音频流管理
其中,openOutput() 和 createTrack() 这两个接口涉及最多。
AudioFlinger 回放录制线程
AndioFlinger 作为 Android 的音频系统引擎,重任之一是负责输入输出流设备的管理及音频流数据的处理传输,这是由回放线程(PlaybackThread 及其派生的子类)和录制线程(RecordThread)进行的,我们简单看看回放线程和录制线程类关系:
- ThreadBase:PlaybackThread 和 RecordThread 的基类;
- RecordThread:录制线程类,由 ThreadBase 派生;
- PlaybackThread:回放线程基类,同由 ThreadBase 派生;
- MixerThread:混音回放线程类,由 PlaybackThread 派生,负责处理标识为 AUDIO_OUTPUT_FLAG_PRIMARY、AUDIO_OUTPUT_FLAG_FAST、AUDIO_OUTPUT_FLAG_DEEP_BUFFER 的音频流,MixerThread 可以把多个音轨的数据混音后再输出;
- DirectOutputThread:直输回放线程类,由 PlaybackThread 派生,负责处理标识为 AUDIO_OUTPUT_FLAG_DIRECT 的音频流,这种音频流数据不需要软件混音,直接输出到音频设备即可;
- DuplicatingThread:复制回放线程类,由 MixerThread 派生,负责复制音频流数据到其他输出设备,使用场景如主声卡设备、蓝牙耳机设备、USB 声卡设备同时输出;
- OffloadThread:硬解回放线程类,由 DirectOutputThread 派生,负责处理标识为 AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD 的音频流,这种音频流未经软件解码的(一般是 MP3、AAC 等格式的数据),需要输出到硬件解码器,由硬件解码器解码成 PCM 数据。
从 Audio HAL 中,我们通常看到如下 4 种输出流设备,分别对应着不同的播放场景:
- 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 回放线程实例。
下图简单描述 AudioTrack、PlaybackThread、输出流设备三者的对应关系:
?
AT和AF交互的流程
- AT调用createTrack,得到一个IAudioTrack对象。
- AT调用IAudioTrack对象的start,表示准备写数据了。
- AT通过write写数据,这个过程和audio_track_cblk_t有着密切关系。
- 最后AT调用IAudioTrack的stop或delete IAudioTrack结束工作。
AudioTrack 构造过程
当我们构造一个 AudioTrack 实例时(以 MODE_STREAM/TRANSFER_SYNC 模式为例,这也是最常用的模式了,此时 sharedBuffer 为空),系统都发生了什么事?阐述下大致流程:
1. 如果 cbf(audioCallback 回调函数)非空,那么创建 AudioTrackThread 线程处理 audioCallback 回调函数(MODE_STREAM 模式时,cbf 为空);
2. 根据 streamType(流类型)、flags(输出标识)等参数调用 AudioSystem::getOutputForAttr();经过一系列的调用,进入 AudioPolicyManager::getOutputForDevice():
- 如果输出标识置了 AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD 或 AUDIO_OUTPUT_FLAG_DIRECT,那么最终调用 AudioFlinger::openOutput() 打开输出标识对应的输出流设备并创建相应的 PlaybackThread,保存该 PlaybackThread 对应的 audio_io_handle_t 给 AudioTrack;
- 如果输出标识是其他类型,那么根据策略选择一个输出流设备和 PlaybackThread,并保存该 PlaybackThread 对应的 audio_io_handle_t 给 AudioTrack;别忘了在 3.4. AudioFlinger 回放录制线程 小节中提到:系统启动时,就已经打开 primary_out、low_latency、deep_buffer 这三种输出流设备,并创建对应的 PlaybackThread 了;
3. 通过 Binder 机制调用 AudioFlinger::createTrack()(注意 step2 中 AudioTrack 已经拿到一个 audio_io_handle_t 了,此时把这个 audio_io_handle_t 传入给 createTrack()):
- 根据传入的 audio_io_handle_t 找到它对应的 PlaybackThread;
- PlaybackThread 新建一个音频流管理对象 Track;Track 构造时会分配一块匿名共享内存用于 AudioFlinger 与 AudioTrack 的数据交换缓冲区(FIFO)及其控制块(audio_track_cblk_t),并创建一个 AudioTrackServerProxy 对象(PlaybackThread 将使用它从 FIFO 上取得可读数据的位置);
- 最后新建一个 Track 的通讯代理 TrackHandle,并以 IAudioTrack 作为返回值给 AudioTrack(TrackHandle、BnAudioTrack、BpAudioTrack、IAudioTrack 的关系见上一个小节);
4. 通过 IAudioTrack 接口,取得 AudioFlinger 中的 FIFO 控制块(audio_track_cblk_t),由此再计算得到 FIFO 的首地址;
5. 创建一个 AudioTrackClientProxy 对象(AudioTrack 将使用它从 FIFO 上取得可用空间的位置);
AudioTrack 由此建立了和 AudioFlinger 的全部联系工作:
- 通过 IAudioTrack 接口可以控制该音轨的状态,例如 start、stop、pause;
- 持续写入数据到 FIFO 上,实现音频连续播放;
- 通过 audio_io_handle_t,可以找到它对应的 PlaybackThread,从而查询该 PlaybackThread 的相关信息,如所设置的采样率、格式等等。
构造 1 个 AudioTrack 实例时,AudioFlinger 会有 1 个 PlaybackThread 实例、1 个 Track 实例、1 个 TrackHandle 实例、1 个 AudioTrackServerProxy 实例、1 块 FIFO 与之对应。
|