Android AAudio介绍及流程分析

📅 2026/8/1 9:31:52 👁️ 阅读次数 📝 编程学习
Android AAudio介绍及流程分析

AAudio 是 Android 系统提供的一种高性能、低延迟的原生 C API 音频库。

源码下的使用样例及测试程序:

frameworks/av/media/libaaudio/examples/write_sine/

为什么可以做到低延时?

1.使用mmap机制减少拷贝。

在支持的硬件上,AAudio 可以进入 MMAP 模式。
在普通模式下,音频数据需要在应用层、系统音频引擎和硬件驱动之间多次拷贝。而在 MMAP 模式下,数据直接写入一个应用和硬件共享的内存区域。这种方式极大地降低了 CPU 占用和延迟。

AAudio Sharing Mode分为两种:

  • AAUDIO_SHARING_MODE_SHARED
  • AAUDIO_SHARING_MODE_EXCLUSIVE

SHARED模式为默认模式,可以支持多应用程序同时使用,多个客户端播放时会在AAudio Server中进行混音,所以会多出一个缓冲区,这种模式下拥有双重缓冲区,会增加时延。

AAudioStream_setBufferSizeInFrames和AAudioStreamBuilder_setBufferCapacityInFrames ** 主要也是针对AAudio Server中的缓冲区进行设定,capacity最大可设定为32x1024。另一个缓冲区是HAL层创建的“共享内存”。

EXCLUSIVE模式只有一个缓冲区,即HAL层创建的"共享内存",capacity size和burst size是由HAL来决定,但buffer size依然是由上层设定。

2.减小buffer size,降低延时。在确保不发生underrun的情况下,尽量使用最小buffer size。

AAudioStream_getFramesPerBurst每次消耗的数据大小。

AAudioStream_setBufferSizeInFramesringbuffer size,由应用层设置,一般要为burst frames的整数倍,默认是2倍。可以在播放过程中动态调整。

AAudioStreamBuilder_setBufferCapacityInFramesringbuffer size最大限制,由应用层设置,动态调整buffer size时不能超过这个值。

buffer size较小的时候,cpu稍微抖动就会发生underrun出现断音,闲置情况单独使用write_sine播放,使用512的buffer size,不会发生断音,此时延时也最低。


3.使用实时高优先级回调线程取数据

AAudio数据传输有两种模式:

  • Read/Write同步模式
  • callback回调异步模式

write_sine对应的是同步模式,线程优先级低,所以很容易被cpu抖动产生影响,其它进程有操作时,断音明显。

write_sine_callback 对于的是回调模式,AAudio 会在一个专门的高优先级线程中自动调用它,优先级极高且由系统调度,不容易受应用主线程或其他繁忙任务的影响。

分别对比同步模式和异步模式两种情况下线程的状态:

1|RTD1325A16:/ # ps -T -p 5973 -o USER,PID,TID,PRI,RTPRIO,SCHED,PCY,CMD USER PID TID PRI RTPRIO SCH PCY CMD root 5973 5973 19 - 0 fg write_sine_call root 5973 5974 19 - 0 fg binder:5973_1 root 5973 5975 19 - 0 fg binder:5973_2 root 5973 5982 42 2 1 fg AAudio_1 RTD1325A16:/ # ps -T -p 3467 -o USER,PID,TID,PRI,RTPRIO,SCHED,PCY,CMD USER PID TID PRI RTPRIO SCH PCY CMD root 3467 3467 19 - 0 fg write_sine root 3467 3468 19 - 0 fg binder:3467_1 root 3467 3469 19 - 0 fg binder:3467_2

可以看到回调模式下,会多出一个AAudio创建的线程,其优先级(PRI)更高,并且属于实时线程(RTPRIO),调度模式(SCH)为FIFO,普通线程调度模式为NORMAL。

如何配置audio_policy_configuration.xml

<mixPort name="mmap_no_irq_out" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT AUDIO_OUTPUT_FLAG_MMAP_NOIRQ" >
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="44100 48000"
channelMasks="AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_5POINT1"/>
</mixPort>

A good blog for reference.

AA​​​​​​​【Android Audio】AAudio 架构讲解以及实现范例 (附带visio流程图)_aaudio demo-CSDN博客

open流程

shared模式流程会复用exclusive mode,如果只是exclusive mode,会跳过2-10步。

1 Aaudiostreambuilder_openstream 2 AudioStreamInternalPlay::open 这部分 AudioStreamInternalPlay 运行在client进程下。share mode 为AAUDIO_SHARING_MODE_SHARED 3 AudioStreamInternal::open 4 AAudioService::openStream 5 AAudioServiceStreamShared::open 6 AAudioServiceStreamBase::open 7 AAudioEndpointManager::openEndpoint 8 AAudioEndpointManager::openSharedEndpoint 9 AAudioServiceEndpointPlay::open && AAudioMixer::allocate,这里创建第一个缓冲区,同时在构造方法中,创建 AAudioServiceEndpointShared,将 AudioStreamInternalPlay 作为参数传入。 10 AAudioServiceEndpointShared::open 将share mode设置为 AAUDIO_SHARING_MODE_EXCLUSIVE ,再次打开 AudioStreamInternalPlay。 11 AudioStreamInternalPlay::open 此时 AudioStreamInternalPlay 运行在service进程下,share mode 为 AAUDIO_SHARING_MODE_EXCLUSIVE 12 AudioStreamInternal::open 13 AAudioService::openStream 14 AAudioServiceStreamMMAP::open 15 AAudioServiceStreamBase::open 16 AAudioEndpointManager::openEndpoint 17 AAudioEndpointManager::openExclusiveEndpoint 18 AAudioServiceEndpointMMAP::open 19 AAudioServiceEndpointMMAP::openWithConfig 20 MmapStreamInterface::openMmapStream 21 AudioFlinger::openMmapStream && MmapStreamInterface::createMmapBuffer 这里最终到HAL层创建第二个缓冲区

start 流程

与open流程类似,需要注意的是它会在aaudio service中会创建一个混音线程。 AAudioServiceEndpointShared::startStream 第一个请求 sartStream 的时候,创建混音线程 AAudioServiceEndpointShared::startSharingThread_l


write 流程

AAudioStream_write() AudioStreamInternalPlay::write AudioStreamInternalPlay::processDataNow AAudioFlowGraph::process() 写入第一个缓冲区 FIFO RingBuffer AAudioServiceEndpointPlay::callbackLoop 唤起混音线程,处理所有客户端传过来的buffer AAudioMixer::mix AAudioServiceEndpointShared::write AudioStreamInternalPlay::processDataNow AAudioFlowGraph::process() 写入第二个缓冲区,HAL创建的共享缓冲区