欢迎访问云渡桥财经网

万字长文吃透RK平台音频开发!从架构到实战,调试工具全收录

频道:外汇市场 日期: 浏览:3659

音频功能是嵌入式设备的核心能力之一,尤其在Rockchip瑞芯微)全系列芯片覆盖的智能音箱、IPC摄像头、平板、IoT设备等场景中,音频开发更是高频需求。本文将从音频基础原理出发,全面拆解RK平台基于ALSA/ASoC的音频架构、芯片资源特性、驱动开发流程及调试方法,手把手教你搞定RK平台音频开发!

一、音频开发基础:从模拟到数字的核心概念

1.1声音的数字化过程

声音本质是空气振动的机械波,SoC处理音频需完成「模拟→数字→模拟」的转换,核心依赖三类芯片:

ADC:将模拟电信号采样量化为数字值

DAC:将数字值还原为模拟电信号

CODEC:同时包含ADC和DAC的芯片

声波 ──► 麦克风 ──► 模拟电信号 ──► ADC ──► 数字信号 ──► SoC 处理                           │扬声器 ◄── 模拟电信号 ◄── DAC ◄── 数字信号 ◄─── 回放处理

1.2数字音频关键参数

音频质量和传输效率由核心参数决定,也是开发中需重点配置的内容:

参数 含义 常见值
采样率 每秒采集的样本点数 8k, 16k, 44.1k, 48k, 96k, 192k Hz
位深 每个样本占用的bit数 16, 24, 32 bits
通道数 同时传输的独立音频流数量 1(单声道), 2(立体声), 4, 8, 16
比特率 每秒传输的总bit数 采样率×位深×通道数

计算示例:48kHz采样率、16bit位深、立体声(2通道)

比特率= 48000 × 16 × 2 = 1,536,000 bps = 1.536 Mbps

1.3为什么需要DAI?

SoC与外部CODEC之间传输数字音频时,需约定「何时发、如何分声道、如何同步」,DAI(数字音频接口就是解决这些问题的协议规范,常见类型:I2S、PDM、TDM、SPDIF。

二、RK平台音频核心架构:ALSA/ASoC

RK平台音频驱动基于Linux ALSA/ASoC框架构建,是开发的核心基础,需先理清层级和组件分工。

2.1 Linux音频子系统层次结构

┌─────────────────────────────────────────────┐│       用户空间应用程序        ││    (aplay, tinypcminfo, 音乐播放器)   │├─────────────────────────────────────────────┤│     libasound(ALSA用户库)     ││  (default, hw, plug, dmix, pulse 插件) │├─────────────────────────────────────────────┤│      ALSAKernelCore       ││ (PCM中间层, 控制中间层,Mixer中间层)   │├──────────────────┬──────────────────────────┤│ ASoCCore  │ ALSACore      ││(snd_soc_core) │(snd_pcm, snd_control) │├──────────────────┼──────────────────────────┤│ CPUDAIDriver│ CodecDriver     ││ (I2S/PDM/SAI) │ (ES8388/RT5645/RK817) │├──────────────────┼──────────────────────────┤│ DMAEngine  │ I2C/SPIBus     ││(DMA数据传输)  │(Codec寄存器读写)    │└──────────────────┴──────────────────────────┘

(1)内核层接口(/dev/snd/*设备节点)

设备节点 说明
controlCn 声卡n的控件(音量、静音、路由等)
pcmCnDdp 声卡n的设备d的playback子设备
pcmCnDdc 声卡n的设备d的capture子设备
timer 全局定时器
seq MIDI序列器

(2)用户层接口(libasound库+插件)

插件 说明
default 默认PCM,指向hw:0,0
hw 直接访问硬件,绕过所有插件
plug 自动格式转换
dmix 多路混音(多个应用同时播放)
pulse 转发给PulseAudio/PipeWire

2.2 ASoC三层架构:解决驱动复用问题

ASoC将音频驱动拆分为三个正交组件,是嵌入式音频开发的核心设计,大幅减少代码冗余:

┌─────────────────────────────────────────────────┐│       Machine Driver           ││  描述:哪个 CPU DAI 连接哪个 CODEC        ││  示例:simple-audio-card (通用 Machine Driver) ││     rockchip_multicodecs.c        │├──────────────────────┬──────────────────────────┤│  CPU DAI / Platform │  Codec Driver      ││  Driver       │             ││           │             ││  rockchip_i2s_tdm.c│  es8388.c       ││  rockchip_sai.c  │  rt5645.c       ││  rockchip_pdm.c  │  rk817_codec.c     ││  rockchip_spdif.c │  dmic.c        ││           │  hdmi-codec.c     ││  DMAEngine     │  I2C/SPI 寄存器读写   │└──────────────────────┴──────────────────────────┘

三层分离的价值

假设3块板子用同一RK SoC,但搭配不同CODEC(ES8388/RT5645/TAS5731):

•CPU Driver:只需写1份,3块板子共用

•Codec Driver:每种CODEC写1份,可复用至其他SoC

•Machine Driver:每块板子写1份(可复用Simple Card框架,仅需配置DTS)

无ASoC时代码量:板子数× SoC类型× Codec类型(乘法增长);

有ASoC时代码量:Codec数+ SoC数+板子数(加法增长)。

2.3音频数据流完整路径(以播放WAV为例)

wKgZO2oWKXWAVevrAAHxzoiR7pk695.png

关键步骤拆解:

1.open:应用打开PCM设备(如/dev/snd/pcmC0D0p),触发snd_pcm_open(),建立substream;

2.hw_params:设置采样率/位深/通道数,DAI驱动配置BCLK/LRCK频率,Codec驱动配置ADC/DAC参数;

3.prepare:分配DMA缓冲区,配置DMAEngine的源/目的地址、传输大小;

4.start:启动DMA传输,自动从内存搬运数据到DAI FIFO,CPU无需参与;

5.运行中:DMA以period为单位传输,每完成一个period触发中断,更新硬件指针;

6.stop:停止DMA,释放资源。

2.4核心概念:PCM、Substream、Period、Buffer

开发中频繁接触的核心名词,理解后才能定位问题:

概念 含义 类比
PCM设备 ALSA中处理音频数据流的设备 一个“音频管道”
Substream PCM设备下的子流(playback/capture各一个) 管道中的一个方向
Buffer 内核分配的环形缓冲区,存储待播放/已录制数据 一个大水库
Period Buffer切分为多个period,DMA每次传输一个period 每次从水库放/收一桶水
DMA中断 每完成一个period触发一次中断 水桶满/空的铃铛

Buffer(环形缓冲区)┌─────────────────────────────────────────────┐│ Period0 │ Period1 │ Period2 │ Period3 │ ... ││◄───── period_size ─────►          ││                       ││ hw_ptr(硬件指针)              ││    ▼                   ││ appl_ptr(应用指针)             ││       ▼               │└─────────────────────────────────────────────┘# 常见异常如果DMA来不及取数据(playback时buffer空)→ XRUN(Underrun)→ 爆音如果DMA来不及存数据(capture时buffer满)→ XRUN(Overrun)→ 丢数据

三、RK全系列芯片音频资源全景

不同RK芯片的音频资源差异较大,开发前需先匹配芯片特性,以下是核心芯片的资源汇总及关键特性:

3.1全芯片音频资源汇总表

芯片 I2S/SAI PDM SPDIF ASRC VAD HDMI Audio 内置Codec
RK3576 SAI0/1: 4TX/4RX

SAI2/3/4: 1TX/1RX

PDM0/1: 8ch TX×2, RX×2 2×2ch + 2×4ch - HDMI TX ×1 (8ch I2S, ARC) 2ch DAC
RK3588 I2S0: 8ch TX或RX

I2S1: 8ch TX+RX

I2S2/3: 2ch

PDM0/1: 8ch TX×2, RX×2 - Yes HDMI TX×2 + RX 2ch DAC
RK3568 I2S0: 8ch (HDMI)

I2S1: 8ch

I2S2/3: 2ch

PDM: 8ch TX+RX - - I2S0专用 3ch ADC + 2ch DAC
RK3562 SAI: 2ch PDM: 8ch TX - - - -
RK3528 SAI: 2ch PDM: 8ch TX - - - -
RK3506 - PDM - - - - -
RK3399 I2S0/1/2: 8ch - TX+RX - - I2S0专用 -
RK3368 I2S0/1/2: 2ch

I2S0: 8ch (TDM)

- TX+RX - - - -
RK3328 I2S0/1/2: 2ch

I2S: 8ch (TDM)

PDM: 8ch TX - - - -
RK3326/PX30 I2S1/2: 2ch

I2S0: 8ch (TDM)

PDM: 8ch - - - - -
RK3308 I2S_2CH×2

I2S_8CH×2

I2S_16CH×1

PDM_8CH: 8ch TX+RX - Yes HDMI ARC 8ch ADC
RK312X I2S_8CH, I2S_2CH - - - - - 内置
RK3288 I2S0: 8ch - TX - - - -
RK322X I2S0: 2ch

I2S0: 8ch (TDM)

- TX - - - -
RV1126/RV1109 I2S1/2: 2ch

I2S0: 8ch (TDM)

PDM: 8ch TX - - - -
RV1126B/RV1126BP - - - - AOV - ACodec
RV1106/RV1103 - - - - AOV - ACodec
RK1808 I2S1: 2ch

I2S0: 8ch (TDM)

PDM: 8ch - - - - -
RK2118/RK2116 - - - - - - -

重要说明

•RK3576的SAI接口功能等效于I2S-TDM,仅命名不同;

•RK3588音频资源最丰富(VAD、双HDMI音频、HDMI RX);

•RK3308是语音专用芯片,麦克风接口和VAD能力最强;

•RV1106/RV1126B系列采用ACODEC低功耗音频方案。

3.2核心芯片音频资源详解

(1)RK3576(SAI接口为主)

SAI接口 TX通道 RX通道 特性
SAI0 4 lanes 4 lanes 高性能,支持I2S/TDM/PCM
SAI1 4 lanes 4 lanes 高性能,支持I2S/TDM/PCM
SAI2 1 lane 1 lane 基本型,支持I2S/TDM/PCM
SAI3 1 lane 1 lane 基本型,支持I2S/TDM/PCM
SAI4 1 lane 1 lane 基本型,支持I2S/TDM/PCM

•支持格式:I2S(3种对齐)、PCM(4种时序)、TDM(5种移位);

•位深:16~32bits,采样率最高192kHz;

•SPDIF:TX×2(最高192kHz)、RX×2(最高384kHz);

•ASRC:双2通道+双4通道,支持异步采样率转换(如蓝牙44.1kHz转系统48kHz)。

(2)RK3588(I2S接口为主)

I2S接口 TX能力 RX能力 特点
I2S0 8ch TX或8ch RX 8ch TX或8ch RX 8通道,TDM模式
I2S1 8ch TX+8ch RX 8ch TX+8ch RX 8通道全双工
I2S2 2ch TX+2ch RX 2ch TX+2ch RX 2通道
I2S3 2ch TX+2ch RX 2ch TX+2ch RX 2通道
I2S4-10 集成到显示控制器 - HDMI/eDP/HDMI RX专用

时钟源:内部PLL、分数PLL(高精度)、外部时钟、晶振分频;

•PDM:4条数据路径,支持8单声道/4立体声MIC,采样率覆盖8k~192kHz。

3.3芯片选型建议

应用场景 推荐芯片 理由
智能音箱(8 MIC阵列+ VAD) RK3308 语音专用,8ch ADC + 8ch PDM + VAD
多路音频输出 RK3588 最多的I2S资源,双HDMI音频
平板/盒子 RK3568 丰富的I2S + PDM,内置Codec
IPC摄像头(音频录制) RV1126/RV1106 PDM 8ch + AOV(Always On Video)
IoT RK3562/RK3506 基础音频支持
多媒体+ AI RK3576 SAI高性能+ ASRC异步采样转换

3.4 PDM控制器版本差异

RK的PDM控制器迭代了3个版本,开发时需匹配对应驱动:

版本 时钟频率 修复/新增 使用芯片
V1 12.048 / 2.822 / 3.072 MHz 基础版本 RK3328
V2 12.048 / 2.822 / 3.072 MHz 修复HPF/0dB增益问题 PX30/RK3326/RK1808/RK3308
V3 1.024/1.411/1.536/4.096/5.644/6.144 MHz 新增高低频时钟 RK2108/RK3568/RV1126/RV1109

四、RK音频驱动开发:代码结构与注册流程

4.1驱动文件组织结构

(1)DAI + Platform驱动(kernel/sound/soc/rockchip/)

文件 功能 备注
rockchip_i2s.c 旧版I2S DAI 支持I2S/PCM,老芯片用
rockchip_i2s_tdm.c 新版I2S-TDM DAI 支持I2S/PCM/TDM,新芯片用
rockchip_sai.c SAI DAI RK3576/RK3562等SAI命名芯片
rockchip_pdm.c PDM DAI 数字麦克风接口
rockchip_pdm_v2.c PDM V2 DAI V2版本PDM
rockchip_spdif.c SPDIF TX DAI 数字音频发送
rockchip_spdifrx.c SPDIF RX DAI 数字音频接收
rockchip_vad.c VAD DAI 语音活动检测
rockchip_asrc.c ASRC DAI 异步采样率转换
rockchip_pcm.c PCM数据流 DMA控制
rockchip_multicodecs.c Multi Codecs Machine 一DAI多CODEC
rockchip_multi_dais.c Combo DAI Machine 多DAI组合
rockchip_multi_dais_pcm.c Combo DAI PCM 与Combo DAI协同

(2)Codec驱动(kernel/sound/soc/codecs/)

文件 功能 备注
rk3308_codec.c RK3308内置8ch ADC 语音专用
rk3328_codec.c RK3328内置CODEC -
rk312x_codec.c RK312X内置CODEC -
rk_codec_digital.c 数字CODEC 对接外部模拟(RK812)
rk817_codec.c RK817/RK809 PMIC Codec PMIC中的音频
hdmi-codec.c HDMI Codec 通用HDMI音频
dmic.c 数字麦克风CODEC I2S DMIC / PDM DMIC
dummy-codec.c 占位CODEC 直通/无codec场景

4.2 Machine Driver注册流程(以rockchip_multicodecs.c为例)

module_init() │ ▼rockchip_multicodecs_probe() │ ├──►snd_soc_set_runtime_data()  // 设置runtime参数 ├──►snd_soc_card_register()    // 注册声卡 │   │ │   ├──►snd_soc_instantiate_card() │   │   │ │   │   ├──►遍历codec_link,绑定CODECDAI │   │   ├──►遍历dai_link,绑定CPUDAI │   │   ├──►snd_soc_dai_link_init() │   │   │   │ │   │   │   ├──►snd_soc_new_pcms()   // 创建PCM设备 │   │   │   └──►snd_soc_dapm_new_widgets()// 创建DAPM widgets │   │   │ │   │   └──►snd_card_register()      // 注册ALSA声卡 │   │       │ │   │       └──►/dev/snd/pcmC*D*p, /dev/snd/controlC* │   │ │   └──►声卡出现在/proc/asound/cards │ └──►注册完成,等待用户空间open()

4.3 Simple Card注册流程(RK主流方案)

Simple Card是ASoC通用Machine驱动,RK大量用于简化声卡配置,核心依赖DTS配置:

DTS中定义simple-audio-card    │    ▼simple-card.c的probe()    │    ├──► simple_dai_link_of_tdm()   // 解析DAI link    ├──► simple_card_parse_of()    // 解析DTS属性    │    │    │    ├──► 读取simple-audio-card,name    │    ├──► 读取simple-audio-card,format    │    ├──► 读取simple-audio-card,mclk-fs    │    ├──► 读取bitclock-master / frame-master    │    └──► 读取dai-tdm-slot-num / dai-tdm-slot-width    │    ├──► asoc_simple_init_dai_link()  // 初始化dai_link结构    ├──► devm_snd_soc_register_card() // 注册声卡    └──► 声卡出现在/proc/asound/cards

4.4 Android特有的Audio HAL层

Android应用不直接调用ALSA,而是通过Audio HAL间接访问,架构如下:

Android 应用 (MediaPlayer, AudioTrack)    │    ▼AndroidFramework(AudioFlinger, AudioPolicyService)    │    ▼AudioHAL(libaudio_hw.so)  hardware/rockchip/audio/tinyalsa_hal/audio_hw.c    │    ├──►adev_open_output_stream() // 打开输出流    ├──►out_write()        // 写入音频数据    └──►out_standby()       // 进入待机    │    ▼TinyALSA 库 (libtinyalsa.so)  external/tinyalsa/    │    ├──►pcm_open()  // 打开PCM设备    ├──►pcm_write()  // 写入PCM数据    ├──►pcm_read()  // 读取PCM数据    └──►pcm_close()  // 关闭PCM设备    │    ▼ALSAKernel(/dev/snd/pcmC*D*p)

Android Audio HAL关键文件:

文件/路径 作用
hardware/rockchip/audio/tinyalsa_hal/audio_hw.c Audio HAL主实现
hardware/rockchip/audio/tinyalsa_hal/codec_config/ 各Codec的路由配置头文件
external/tinyalsa/ TinyALSA库(Android轻量级ALSA用户库)
device/rockchip/common/audio_policy_volumes_drc.xml 音量策略配置

五、调试神器:RK音频开发必备命令

调试是音频开发的核心环节,以下命令覆盖Linux/Android双平台,解决90%的音频问题。

5.1 Linux/Android通用命令(需root)

# ====== 查看声卡 ======cat/proc/asound/cards# 输出格式:# 0 [声卡名称   ]: 驱动名 - 声卡描述#           声卡描述详情# ====== 查看PCM状态 ======cat/proc/asound/card0/pcm0p/sub0/status # playback状态cat/proc/asound/card0/pcm0c/sub0/status # capture状态# 可能值: OPEN, SETUP, PREPARED, RUNNING, DRAINING, PAUSED, SUSPENDED# ====== 查看硬件参数 ======cat/proc/asound/card0/pcm0p/sub0/hw_params # 当前hw_params# 输出: access, format, subformat, channels, rate, period_size, buffer_size# ====== 查看设备节点 ======ls-l /dev/snd/# ====== 时钟调试 ======cat/sys/kernel/debug/clk/clk_summary | grep -E'i2s|pdm|spdif|sai'# ====== Codec寄存器调试 ======cat/sys/kernel/debug/regmap/*/registers# ====== XRUN调试 ======echo7 > /proc/asound/card0/xrun # 开启XRUN日志dmesg | grep -i xrun# ====== Android Audio HAL日志 ======logcat -s alsa_route  # 查看音频路由变化logcat -s AudioFlinger # 查看AudioFlinger日志

5.2 Linux专用调试命令

# ====== ALSA-utils工具 ======# 播放aplay -D hw:0,0 -r 48000 -c 2 -f S16_LE test.wavaplay -l  # 列出所有声卡和PCM设备aplay -L  # 列出所有PCM名称(含插件)# 录制arecord -D hw:0,0 -r 16000 -c 2 -f S16_LE test.wavarecord -l # 列出所有capture设备# 管道录制(测试延迟)arecord -D hw:0,1 -fcd| aplay -D hw:0,0# 控件操作amixer -c 0 contents    # 列出所有控件amixer -c 0 sset'Playback Path'SPK  # 设置控件值amixer -c 0 sget'Playback Path'   # 获取控件值# 环回测试alsaloop -C hw:0,1 -P hw:0,0 -c 2 -r 48000# ====== ALSA详细调试 ======cat/proc/asound/version  # ALSA版本cat/proc/asound/devices  # 所有ALSA设备cat/proc/asound/timers   # 定时器# ====== ftrace性能分析 ======echofunction> /sys/kernel/debug/tracing/current_tracerechosnd_soc* > /sys/kernel/debug/tracing/set_ftrace_filterecho1 > /sys/kernel/debug/tracing/tracing_on# ... 执行操作 ...echo0 > /sys/kernel/debug/tracing/tracing_oncat/sys/kernel/debug/tracing/trace

5.3 Android专用调试命令

# ====== TinyALSA工具 ======# 播放tinyplay/sdcard/test.wav -D0-d0-p1024-n3# -D: card号, -d: device号, -p: period_size, -n: period数量# 录制tinycap/sdcard/record.wav -D0-d1-c8-r16000-b16-p1024-n3# -c: 通道数, -r: 采样率, -b: 位深(16/24/32)# 查看PCM信息tinypcminfo-D0# 混音器操作tinymix          # 列出所有控件及其值tinymix02        # 设置控件0的值为2(播放路径设为SPK)tinymix"DAC Volume"175 # 按名称设置控件# ====== Android 10+ PCM Dump(抓取原始数据)======touch/data/misc/audioserver/debug.pcmchmod777/data/misc/audioserver/debug.pcmsetenforce0setpropvendor.audio.record5  # 抓取5MB播放数据# 输入数据抓取(Android 12+)touch/data/misc/audioserver/debug_in.pcmchmod777/data/misc/audioserver/debug_in.pcmsetpropvendor.audio.record.in5# 抓取5MB录制数据# ====== Logcat音频调试 ======logcat-s AudioFlinger  # AudioFlinger层日志logcat-s audio_hw    # Audio HAL层日志logcat-s alsa_route   # 音频路由变化logcat-s ALSAModule   # ALSA模块加载日志# ====== 音频属性调试 ======getprop| grep audio   # 查看所有音频相关属性setpropvendor.audio.debug1 # 开启音频调试模式# ====== 音频策略调试 ======dumpsysmedia.audio_flinger # 查看AudioFlinger状态dumpsysmedia.audio_policy  # 查看AudioPolicy状态

5.4声卡调试排查流程图(解决无声/无录制问题)

六、总结

RK平台音频开发的核心是基于ALSA/ASoC框架,掌握「三层驱动架构+芯片资源特性+调试工具」三大核心即可解决绝大多数场景需求:

1.驱动层:Codec Driver负责编解码、CPU DAI Driver负责接口通信、Machine Driver负责组合适配,优先复用Simple Card框架减少开发量;

2.芯片层:根据场景选择芯片(如智能音箱选RK3308,多路音频选RK3588),重点关注DAI接口(I2S/SAI/PDM)和时钟配置;

3.调试层:Linux用ALSA-utils,Android用TinyALSA,结合procfs/regmap/logcat定位问题,按排查流程图解决无声/XRUN等核心问题。

审核编辑 黄宇