一、音频延时全景图:Android音频通路概览、延时的定义与测量方法、常见场景的延时指标

各位同学,咱们今天聊一个老生常谈但又绕不开的话题——音频延时。说实话,我做了这么多年Android音频,最头疼的就是这个“延时”。你想想看,用户唱歌时听到自己的声音慢了半拍,或者视频通话里对方嘴巴动了半天声音才传过来,这种体验基本就是灾难。

所以第一节课,咱们先把全景图铺开。搞清楚音频在Android系统里到底是怎么跑的,延时从哪来,怎么量,以及不同场景下到底多少延时才算“及格”。

1.1 Android音频通路概览

先看一张我画的通路图。别被吓到,其实核心链路就那么几段。

应用层 (App) AudioTrack / AudioRecord 框架层 (Framework) AudioFlinger / Policy HAL 层 HAL / Driver write() mixer thread DSP / Codec 硬件加速 / 重采样 ALSA / tinyalsa 内核驱动层 物理设备 Speaker / Mic ioctl DMA 各环节典型延时分布 App Buffer: 10~40ms Framework Mixer: 5~20ms HAL + Driver: 2~10ms DSP处理: 1~15ms ALSA Buffer: 5~30ms 物理传输: 0.5~2ms 总延时 = 各环节累加,通常 30~120ms

从App调用AudioTrack.write()开始,数据经过Framework的AudioFlinger混音,再到HAL层,最后通过ALSA驱动送到扬声器。反过来录音路径也一样,只是方向相反。

每个环节都会引入延时。我见过不少开发者只盯着App层优化,结果发现底层Buffer一卡,前面全白费。嗯,这里要注意——延时是累加的,短板效应非常明显

核心结论:Android音频通路从App到物理设备,至少经过4~6个缓冲区。每个缓冲区的大小直接决定了延时下限。

1.2 延时的定义与测量方法

什么叫音频延时?说白了就是从声音产生到被听到的时间差。但实际工程里,我们得区分几个概念:

  • 端到端延时 (Round-trip latency):从麦克风采集到扬声器播放的总时间。VoIP、K歌最关心这个。
  • 播放延时 (Output latency):从App写数据到扬声器出声的时间。
  • 录音延时 (Input latency):从麦克风收音到App读到数据的时间。

怎么测?我分享两个我常用的土办法:

方法一:Loopback 硬件测量

用一根音频线把手机耳机孔的输出和输入短接。App播放一个脉冲信号,同时录音。然后看两个脉冲之间的时间差。这个方法最准,但需要硬件转接头。

// 伪代码示意
playPulse();  // 播放脉冲
startRecord();
while (recording) {
    if (detectPulse(recordedData)) {
        latency = currentTime - pulsePlayTime;
        break;
    }
}

方法二:软件时间戳法

Android 从 API 24 开始提供了 AudioTimestamp 接口。可以拿到硬件播放的位置和对应的时间戳。我个人习惯用这个做日常调试,不用额外硬件。

AudioTrack track = new AudioTrack(...);
AudioTimestamp ts = new AudioTimestamp();
// 获取硬件播放位置
track.getTimestamp(ts);
// ts.framePosition 是硬件已播放的帧数
// ts.nanoTime 是对应的系统时间
// 延时 = (App写入帧数 - 硬件播放帧数) / 采样率

小技巧:dumpsys media.audio_flinger 可以快速查看当前AudioFlinger的Buffer配置和延时估算值。我排查问题时经常先跑这条命令。

1.3 常见场景的延时指标

不同场景对延时的容忍度天差地别。咱们直接看表:

场景 可接受延时 优秀延时 关键瓶颈
VoIP 通话 < 150ms < 50ms 录音+网络+播放
K歌 / 耳返 < 30ms < 10ms 播放路径Buffer
直播推流 < 200ms < 80ms 编码+网络+播放
游戏音效 < 50ms < 20ms 播放路径+混音

你看,K歌场景要求最苛刻——30ms以内。为什么?因为人耳对自声音的延时极其敏感。超过30ms,唱歌的人就会觉得“声音跟不上了”,俗称“延迟感”。

我曾经在一个K歌项目里踩过坑。当时用默认的AudioTrack配置,播放延时直接飙到80ms。用户反馈“唱歌像在跟读”。后来我把Buffer大小从默认的4帧改成了2帧,配合PERFORMANCE_MODE_LOW_LATENCY,才压到15ms左右。

避坑指南:千万不要在VoIP或K歌场景里用MODE_STREAM配合大Buffer。我曾经见过有人图省事直接设了256ms的Buffer,结果用户投诉“声音对不上嘴型”。记住:低延时场景必须用MODE_STATIC或极小的Stream Buffer

再说直播。直播的延时容忍度其实比K歌高,因为用户通常不介意看到画面比声音晚一点点。但推流端(主播侧)的耳返延时必须低,否则主播自己唱不下去。所以直播场景里,本地耳返路径和推流路径要分开优化

VoIP通话呢?150ms以内是行业标准。但如果你能做到50ms以下,用户体验会有质的飞跃。我记得有一次帮一个VoIP厂商优化,他们原本延时120ms,用户反馈“还行”。优化到40ms后,用户说“感觉像面对面说话”。

小结

这一章咱们把全景图铺开了。你知道了音频数据在Android系统里怎么流动,延时怎么定义和测量,以及不同场景下该追求什么指标。说白了,优化延时之前,先得知道你的目标是多少

下一章我会深入讲AudioTrack和AudioRecord的低延时配置,包括Buffer大小怎么选、PerformanceMode怎么用、以及那些坑了我好几年的API细节。到时候咱们手把手调参数。


公众号:蓝海资料掘金营,微信deep3321