Android TV Audio基本框架及启动流程分析

一、Android Audio基本框架:
Android TV Audio基本框架及启动流程分析_第1张图片

1.Audio 是整个 Android 平台非常重要的一个组成部分,负责音频数据的采集和输出、音频流的控制、音频设备的管理、音量调节等,主要包括如下部分:

Audio Application Framework:音频应用框架

AudioTrack:负责回放数据的输出,属 Android 应用框架 API 类

AudioRecord:负责录音数据的采集,属 Android 应用框架 API 类

AudioSystem: 负责音频事务的综合管理,属 Android 应用框架 API 类

Audio Native Framework:音频本地框架

AudioTrack:负责回放数据的输出,属 Android 本地框架 API 类

AudioRecord:负责录音数据的采集,属 Android 本地框架 API 类

AudioSystem: 负责音频事务的综合管理,属 Android 本地框架 API 类

Audio Services:音频服务

AudioPolicyService:音频策略的制定者,负责音频设备切换的策略抉择、音量调节策略等

AudioFlinger:音频策略的执行者,负责输入输出流设备的管理及音频流数据的处理传输

Audio HAL:音频硬件抽象层,负责与音频硬件设备的交互,由 AudioFlinger 直接调用。

与 Audio 强相关的有 MultiMedia,MultiMedia 负责音视频的编解码,MultiMedia 将解码后的数据通过 AudioTrack 输出,而 AudioRecord 采集的录音数据交由 MultiMedia 进行编码。

2.播放声音可以使用 MediaPlayer 和 AudioTrack,两者都提供 Java API 给应用开发者使用。两者的差别在于:MediaPlayer 可以播放多种格式的音源,如 mp3、flac、wma、ogg、wav 等,而 AudioTrack 只能播放解码后的 PCM 数据流。从上面 Android 音频系统架构图来看:MediaPlayer 在 Native 层会创建对应的音频解码器和一个 AudioTrack,解码后的数据交由 AudioTrack 输出。所以 MediaPlayer 的应用场景更广,一般情况下使用它也更方便;只有一些对声音时延要求非常苛刻的应用场景才需要用到 AudioTrack。

二、Android AudioFlinger/AudioPolicyService启动流程
Android TV Audio基本框架及启动流程分析_第2张图片
PlaybackThread在哪里启动的??

其中 mpClientInterface->openOutput() 最终会调用到 AudioFlinger::openOutput():打开输出流设备,并创建 PlaybackThread 对象:

系统启动时,就已经打开 primary_out、low_latency、deep_buffer 这三种输出流设备,并创建对应的 MixerThread 了;而此时 DirectOutputThread 与 OffloadThread 不会被创建,直到标识为 AUDIO_OUTPUT_FLAG_DIRECT/AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD 的音频流需要输出时,才开始创建 DirectOutputThread/OffloadThread 和打开 direct_out/compress_offload 设备。

AudioPolicyManager 的构造函数将解析音频策略配置文件,从而获取到设备所支持的音频设备信息(包括设备是否支持 Offload、Direct 模式输出,各输入输出 profile 所支持的采样率、通道数、数据格式等),加载全部 HwModule,为之创建所有非 direct 输出类型的 outputStream 和所有 inputStream,并创建相应的 playbackThread 或 recordThread 线程。需要注意的是,Android 7.0上的音频策略配置文件开始使用 XML 格式,其文件名为 audio_policy_configuration.xml,而在之前的版本上音频策略配置文件为 audio_policy.conf。

AndioFlinger 作为 Android 的音频系统引擎,重任之一是负责输入输出流设备的管理及音频流数据的处理传输,这是由回放线程(PlaybackThread 及其派生的子类)和录制线程(RecordThread)进行的,我们简单看看回放线程和录制线程类关系:
Android TV Audio基本框架及启动流程分析_第3张图片
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 数据

PlaybackThread 与输出流设备的关系:PlaybackThread 实例与输出流设备是一一对应的,比方说 OffloadThread 只会将音频数据输出到 compress_offload 设备中,MixerThread(with FastMixer) 只会将音频数据输出到 low_latency 设备中。

从 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 回放线程实例

三、Audio Track 应用跟踪流程
Android TV Audio基本框架及启动流程分析_第4张图片
伪代码:
/**

  • 采样率(默认44100,每秒44100个点)
    /
    private int sampleRateInHz = 44100;
    /
    *
  • 声道(默认单声道)
    /
    private int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;
    /
    *
  • 编码率(默认ENCODING_PCM_16BIT)
    /
    private int encodingBitrate = AudioFormat.ENCODING_PCM_16BIT;
    private int recBufSize = 0;
    private int playBufSize = 0;
    recBufSize = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, encodingBitrate);
    playBufSize = AudioTrack.getMinBufferSize(sampleRateInHz, channelConfig, encodingBitrate);
    audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRateInHz, channelConfig, encodingBitrate, recBufSize);
    audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRateInHz, channelConfig, encodingBitrate, playBufSize, AudioTrack.MODE_STREAM);
    blnInstantPlay = true;
    new ThreadInstantPlay().start();
    /
    *
  • 即时播放线程

*/
class ThreadInstantPlay extends Thread
{
@Override
public void run()
{
byte[] bsBuffer = new byte[recBufSize];
audioRecord.startRecording();
audioTrack.play();
while(blnInstantPlay)
{
int line = audioRecord.read(bsBuffer, 0, recBufSize);
byte[] tmpBuf = new byte[line];
System.arraycopy(bsBuffer, 0, tmpBuf, 0, line);
audioTrack.write(tmpBuf, 0, tmpBuf.length);
}
audioTrack.stop();
audioRecord.stop();
}
}
Android TV Audio基本框架及启动流程分析_第5张图片
四、疑问:
1.耳机、Speaker、蓝牙音箱等,PlaybackThread只针对某个设备输出吗?
2.声音输出怎么对接功放驱动的?
3.声音分别调节的策略是怎么样的?
4.配置文件中module,device,flag,stream之间什么关系?

五、参考资料:
https://blog.csdn.net/gjy_it/article/details/71330357
Android 音频系统:从 AudioTrack 到 AudioFlinger

https://blog.csdn.net/axlecho/article/details/78510478
Android Framework学习笔记 – Audio的播放流程

https://blog.csdn.net/qidi_huang/article/details/72912323
Android音频模块启动流程分析

你可能感兴趣的:(Android,Audio)