在 RK 平台上,第三方应用播放音频时,常见现象是系统最终把音频统一拉到 48kHz 再送入混音链路。这样做方便系统混音,但会让 44.1kHz、96kHz、192kHz 这类原始采样率在设备侧被二次处理。
如果目标是音乐播放、专业音频、采集回放一致性验证,或者对时钟抖动和重采样损耗比较敏感,就需要让应用走直出链路,尽量按原采样率输出,而不是默认进入 48kHz mixer。
本文给出的方案核心是:在 AOSP 音频策略里把“可直出”的输出能力暴露出来,在 HAL 侧保证该采样率真的能打开设备通路,再让第三方应用用 AudioTrack 走 direct / offload 路径。这样才能把“看起来支持”变成“实际能出声”。
一、问题背景
RK 平台上的 AOSP 音频框架通常会经过 AudioPolicy、AudioFlinger、HAL、Codec/AMP 这几层。默认混音路径为了兼容性和多应用共享,往往会把 PCM 统一到一个主工作采样率,最常见就是 48kHz。
这个机制本身没有问题,但它不适合所有场景。第三方播放器、离线测试工具、无损播放 App、采样率校验工具,往往希望设备按文件原始采样率输出,减少系统侧重采样和不必要的格式转换。
讨论范围要收窄:这里不讨论 DRM、平台私有播放器、独占式专业音频 API 的定制,也不讨论蓝牙和 USB Audio 的外设链路,只聚焦 RK Android 设备本地扬声器或耳机口的直出能力。
二、核心思路
- 不是“关闭 48kHz”,而是“补齐直出通路”。系统混音仍然可以保留,关键是让满足条件的流有机会绕开 mixer。
- 直出成立的前提有三个:应用侧请求正确,策略层暴露 direct profile,HAL 侧真的支持该采样率和格式。
- 只改 Java 层没用。
AudioTrack申请直出但策略文件没有对应 profile,最后仍然会被回落到 mixer。 - 只改策略也不够。
audio_policy_configuration.xml写了 96kHz,如果 HAL 打不开这个采样率,最终还是失败或回退。 - 最稳妥的办法是把“支持的采样率、声道、格式、输出标志”做成一条闭环链路,按设备能力逐项打通。
常见判断逻辑可以概括成一句话:应用请求的参数必须和 direct profile 一致,并且该输出设备要允许独占/直出打开。
三、落地步骤
先确认硬件链路是否真支持目标采样率。
查看 codec、I2S、PA、DSP 或声卡驱动能力,确认目标文件的采样率不是只在软件层“声明支持”。
1
2
3tinymix
cat /proc/asound/cards
cat /proc/asound/pcm在
audio_policy_configuration.xml中为直出链路增加对应 profile。重点不是只写一个大列表,而是让 direct output profile 明确匹配目标采样率、声道和 PCM 格式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17<module name="primary" halVersion="7.0">
<mixPorts>
<mixPort name="primary output" role="source">
<profile name="primary pcm"
format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="44100,48000,96000"
channelMasks="AUDIO_CHANNEL_OUT_STEREO" />
</mixPort>
<mixPort name="direct pcm" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT">
<profile name="direct pcm 96k"
format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="96000"
channelMasks="AUDIO_CHANNEL_OUT_STEREO" />
</mixPort>
</mixPorts>
</module>让 HAL 的
open_output_stream能按目标采样率建流。如果框架请求 96kHz,HAL 不要悄悄改回 48kHz。应该在参数不支持时明确失败,避免上层误判为直出成功。
在应用侧显式申请 direct 路径。
纯普通
AudioTrack很容易走混音器。第三方 App 需要按能力申请低延迟或 direct 输出,并确保播放参数和设备能力一致。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16AudioAttributes attrs = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build();
AudioFormat format = new AudioFormat.Builder()
.setSampleRate(96000)
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
.setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
.build();
AudioTrack track = new AudioTrack.Builder()
.setAudioAttributes(attrs)
.setAudioFormat(format)
.setTransferMode(AudioTrack.MODE_STREAM)
.build();用日志验证是否真的绕开了 48kHz。
重点看
AudioFlinger、AudioPolicyManager和 HAL 日志,确认输出轨道的采样率没有被重写,且没有回落到 mixer track。1
adb logcat | grep -iE "AudioFlinger|AudioPolicy|primary output|direct"
做回归测试。
分别测试 44.1kHz、48kHz、96kHz 三类文件,确认:
- 48kHz 仍可正常播放
- 目标采样率能直出
- 非支持参数会明确失败,而不是静默重采样
四、常见坑
- 只在 XML 里增加采样率,不改 HAL,最后会出现“策略支持、设备不支持”。
AudioTrack申请了目标采样率,但没有匹配 direct profile,系统仍会回落到 mixer。- 设备同时挂了多个输出端口,策略优先级不清晰时,容易把直出流导到错误端口。
- 厂商做了内部重采样,表面上看是 96kHz 输出,实际上 DAC 前还是被转成 48kHz。
- 仅验证单个文件不够。不同编码、不同声道数、不同 buffer size 都可能触发不同路径。
- 如果系统启用了音效、均衡器、音量增强,直出链路可能被迫回到可混音路径。
五、检查清单
- 已确认目标采样率在硬件和驱动层可打开
-
audio_policy_configuration.xml已为 direct 输出补齐 profile - HAL 不会把目标采样率静默改写成 48kHz
- 第三方应用能显式创建目标采样率的
AudioTrack -
AudioFlinger日志确认没有进入混音重采样路径 - 44.1kHz、48kHz、96kHz 文件都做过实机回归
- 音效和增强链路已评估对直出路径的影响
六、小结
RK 平台上让第三方应用绕过 48kHz 重采样,关键不是某一个开关,而是策略层、HAL 层和应用层一起配合,把直出链路真正打通。
如果只改其中一层,最后大概率还是会回到默认 mixer。把支持能力做成闭环,才能让“原采样率输出”在工程上稳定成立。
- 本文链接: https://blog.hansong.icu/2026/07/24/daily_post_2026_07_24_3/
- 版权声明: 本博客所有文章除特别声明外,均默认采用 CC BY-NC-SA 4.0 许可协议。