Audio简介

1,066 阅读21分钟

基于Android P版本分析

Audio简介

Audio系统是Android中负责音频方面的数据流传输和控制的,也负责音频设备的管理。

架构图

音频架构图.png

从层级上看,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.AudioSystemandroid.media.AudioTrackandroid.media.AudioRecord
本地框架层AudioSystemAudioTrackAudioRecord
AudioFlingerIAudioFlingerIAudioTrackIAudioRecord
硬件抽象层AudioHardwareInterfaceAudioStreamOutAudioStreamIn

各层级之间的调用关系:

audio架构图.drawio.png

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层的封装和代理;

Java_Audio_AudioService.png

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架构的关系:

Java_Native_HAL.drawio.png

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

interfaceDescription
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_class.png

  • 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 DeviceDescription
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和输出流设备三者的对应关系:

AudioTrack_PlaybackThread.png

输出流设备决定了它对应的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_PlaybackThread_Track关系图.png

我们从上图可以看到,在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加载完所有音频接口后,就知道了系统支持的所有音频接口参数,可以为音频输出提供决策。