音频功能是嵌入式设备的核心能力之一,尤其在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为例)

关键步骤拆解:
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等核心问题。
审核编辑 黄宇