深度解析 RK3518 平台 Tinyalsa/ALSA 音频链路:MEDAI-W2 拉流解码器输入源声音获取与 HDMI OUT 音频输出技术详解
产品背景 :MEDAI-W2 是一款基于瑞芯微 RK3518 平台的拉流解码器,可通过网络拉取 RTSP/RTMP 等流媒体信号,解码后输出到 HDMI,并支持 UVC 与 NET1 两路视频通道。设备内置 Web 管理系统(固件版本 2.1),在功能菜单中提供 音频配置:音量调节、静音控制、音频输入源切换(《MEDAI-W2 拉流解码器使用说明书》1.1 节、4.5.3 节)。
前文已解析 FFmpeg 多协议归一拉流、UVC 输入 × MPP 硬解码、RGA + DRM HDMI 视频输出 等链路,聚焦画面 如何从网络/摄像头到 HDMI。本文补全声音 这一半:如何用 Tinyalsa/ALSA 在 RK3518 上获取各路输入源的声音 ,并把它随视频一起从 HDMI OUT 输出------让 MEDAI-W2 输出的是"有声画面",而非静音视频。
一、MEDAI-W2 音频架构总览
1.1 声音从哪来、到哪去
MEDAI-W2 的音频有三类来源、两类去向:
| 维度 | 形态 | 在 RK3518 上的载体 |
|---|---|---|
| 输入源①本地采集 | 板载麦克风 / 线路输入 | 音频 Codec(I2S/TDM 接 RK3518) |
| 输入源②UVC 音频 | UVC 摄像头自带麦克风(UAC) | USB Audio Class,插上即多一张 ALSA 声卡 |
| 输入源③网络流音频 | RTSP/RTMP 里的音轨 | FFmpeg 解封装 + 解码(见《FFmpeg 多协议归一》系列) |
| 输出①HDMI OUT | 声音随视频嵌入 HDMI | HDMI 音频控制器(I2S→HDMI Codec DAI) |
| 输出②UVC/网络 | 声音随画面回传 PC/网络 | USB Audio / RTP 音频(复用视频通道) |
Web 端"音频输入源切换 "正是选择①②③中的哪一个作为当前主音源;"音量调节 / 静音控制"则作用在输出(HDMI)链路上。
1.2 软件栈分层
┌──────────────────────────────────────────────────┐
│ 应用层:MEDAI-W2 音频服务(采集 + 混音 + 输出) │
├──────────────────────────────────────────────────┤
│ 用户空间:tinyalsa(libtinyalsa) / ALSA(libasound) │
│ ├─ pcm.c:capture / playback(直接 ioctl) │
│ └─ mixer.c:音量 / 静音 / 路由 控制 │
├──────────────────────────────────────────────────┤
│ 内核:ALSA SoC(sound/soc/rockchip) │
│ ├─ I2S/TDM DAI(接 Codec) │
│ ├─ USB Audio(UAC,接 UVC 设备) │
│ ├─ HDMI Audio Codec DAI │
│ └─ DMA 引擎 │
├──────────────────────────────────────────────────┤
│ 硬件:RK3518 I2S / USB / HDMI-Audio / Codec │
└──────────────────────────────────────────────────┘
1.3 为什么用 Tinyalsa 而不是完整 ALSA
RK3518 是嵌入式平台,音频要低延迟、确定性强、资源省。两者取舍:
| 维度 | Tinyalsa | 完整 ALSA (libasound) |
|---|---|---|
| 体积/依赖 | 极小,仅 pcm+mixer | 大,带插件体系 |
| 能力 | 直接 ioctl 读写 PCM、控 mixer |
dmix/dshare/重采样/插件链 |
| 延迟 | 低且确定 | 插件可能引入缓冲 |
| 适用 | 嵌入式定点通路(MEDAI-W2 首选) | 桌面多应用混音 |
MEDAI-W2 的音频是"采集 → 直通/混音 → HDMI 输出"的固定通路,不需要 dmix 多应用混音 ,因此用 Tinyalsa 直接操作 PCM 与 mixer 最合适:可控、可预测、省 CPU(与画面侧"零拷贝/卸载"的思路同源)。
二、音频输入源获取(Tinyalsa 采集)
2.1 ALSA 声卡与设备寻址
RK3518 上每个物理音频接口在 ALSA 里是一个 card ,其下有多个 device(PCM 子流):
bash
# 列出所有声卡与采集/播放节点
cat /proc/asound/cards
ls -l /dev/snd/ # pcmC0D0c(采集) / pcmC0D0p(播放) / controlC0 ...
# Tinyalsa 自带工具查看能力
tinypcminfo -D 0 # card 0 各 device 支持的格式/采样率/通道
典型映射(具体编号随设备树而定,开发需实测):
- card 0:板载 Codec(本地 mic/line-in 采集 + HDMI 播放常在同一 SoC 卡内,分不同 device);
- card 1:UVC 设备接入后由 USB Audio 驱动注册的"USB Audio"声卡(UAC)。
2.2 Tinyalsa 采集参考实现
c
/* MEDAI-W2:Tinyalsa 打开一路音频采集(本地 Codec 或 UVC UAC) */
#include <tinyalsa/asoundlib.h>
struct pcm *audio_capture_open(unsigned card, unsigned device,
unsigned rate, unsigned channels)
{
struct pcm_config cfg = {
.channels = channels, /* 1=单声道, 2=立体声 */
.rate = rate, /* 48000 / 44100 */
.format = PCM_FORMAT_S16_LE, /* 16bit 小端 */
.period_size = 1024, /* 每次中断帧数,决定延迟 */
.period_count = 4, /* 缓冲 = period_size*count 帧 */
.start_threshold = 0,
.stop_threshold = 0,
};
struct pcm *pcm = pcm_open(card, device, PCM_IN, &cfg);
if (!pcm || !pcm_is_ready(pcm)) {
/* 设备不存在 / 格式不支持:对应"音频输入源不可用" */
return NULL;
}
return pcm;
}
/* 采集循环:把 PCM 帧读入缓冲,交给混音/编码/输出 */
unsigned char *buf = malloc(pcm_frames_to_bytes(pcm, cfg.period_size));
while (running) {
if (pcm_read(pcm, buf, cfg.period_size) < 0) {
/* 读空/设备断开:UVC 拔插时常见,触发输入源重协商 */
pcm_close(pcm); break;
}
feed_audio_pipeline(buf, cfg.period_size);
}
要点:
period_size直接决定采集端延迟------MEDAI-W2 做直播/监控通常取 1024~2048 帧(约 20~40ms @48k),兼顾延迟与稳定;太小易 XRUN,太大延迟高。
2.3 三类输入源的接入差异
| 输入源 | Tinyalsa 打开方式 | 特别注意 |
|---|---|---|
| 本地 Codec | pcm_open(0, capture_dev, PCM_IN, &cfg) |
采样率/通道以 Codec 能力为准 |
| UVC UAC | pcm_open(uac_card, 0, PCM_IN, &cfg) |
设备插拔导致 card 号变化,需 uevent 重枚举(同《V4L2/UVC》防抖) |
| 网络流音频 | 不经由 Tinyalsa 采集 | FFmpeg 解封装音轨 → 解码出 PCM(见《FFmpeg 多协议归一》),再汇入同一输出管线 |
"音频输入源切换 "(说明书 4.5.3)在代码层就是:停止当前 pcm_close,按新选择重新 pcm_open 对应 card/device,或切换到网络流 PCM 源------与视频侧的"UVC 自动切换"(见《V4L2/UVC》5.x)机制同源:状态机 + 防抖 + 旧源 flush。
三、HDMI OUT 音频输出
3.1 HDMI 音频是什么
HDMI 同时传视频与音频。音频在 HDMI 内以 I2S(LPCM)或 IEC61937(压缩透传 AC3/DTS) 封装随 TMDS 送出。RK3518 上由 I2S DAI → HDMI Audio Codec DAI 接通,内核 ALSA SoC 把它暴露为一个 playback PCM 设备(通常就在 card 0 内,特定 device)。
要让 HDMI 出声,两个前提必须成立:
- Sink 支持该采样率(多数显示器/电视支持 32k/44.1k/48k,罕见 96k);
- HDMI 音频通道已使能(内核 IEC958/HDMI 控件打开,否则只有画面没声音)。
3.2 Tinyalsa 播放到 HDMI 参考实现
c
/* MEDAI-W2:Tinyalsa 把混音后的 PCM 写到 HDMI 播放设备 */
struct pcm *audio_hdmi_open(unsigned card, unsigned hdmi_device,
unsigned rate, unsigned channels)
{
struct pcm_config cfg = {
.channels = channels,
.rate = rate,
.format = PCM_FORMAT_S16_LE,
.period_size = 1024,
.period_count = 4,
.start_threshold = cfg.period_size * 2, /* 攒够两周期再启动 */
.stop_threshold = cfg.period_size * 4,
};
return pcm_open(card, hdmi_device, PCM_OUT, &cfg);
}
/* 输出循环:从混音缓冲取 PCM → pcm_write 到 HDMI */
while (running) {
pull_from_mixer(buf, frames);
if (pcm_write(hdmi_pcm, buf, frames) < 0) {
/* XRUN(欠载):恢复时需重新 prepare,否则静音 */
pcm_prepare(hdmi_pcm);
}
}
3.3 使能 HDMI 音频(Mixer 控制)
HDMI 音频常由一组 IEC958/HDMI 控件 开关控制,需用 mixer 打开:
c
/* 打开 HDMI 音频通道(不同内核控件名略有差异,常见如下) */
struct mixer *mx = mixer_open(card);
struct mixer_ctl *spdif_sw = mixer_get_ctl_by_name(mx, "IEC958 Playback Switch");
struct mixer_ctl *hdmi_sw = mixer_get_ctl_by_name(mx, "HDMI Playback Switch");
if (spdif_sw) mixer_ctl_set_value(spdif_sw, 0, 1); /* 开 */
if (hdmi_sw) mixer_ctl_set_value(hdmi_sw, 0, 1); /* 开 */
/* 必要时写 IEC958 状态字(采样率/类别),部分 Sink 严格要求 */
struct mixer_ctl *def = mixer_get_ctl_by_name(mx, "IEC958 Playback Default");
if (def) mixer_ctl_set_value(def, 0, iec958_status_for(rate));
mixer_close(mx);
经验:很多"HDMI 有画面没声音"的根因就是 IEC958/HDMI 控件没打开 或 采样率与 Sink 不匹配------排查第一刀应打在这里,而非应用层。
四、音量 / 静音控制(说明书 4.5.3)
Web 端"音量控制(0~100%)"与"静音开关"对应两类实现:
c
/* 方式一:走 ALSA mixer(硬件/驱动级音量,最干净) */
struct mixer *mx = mixer_open(card);
struct mixer_ctl *vol = mixer_get_ctl_by_name(mx, "Master Playback Volume");
mixer_ctl_set_value(vol, 0, vol_0_100); /* 0~100 → 线性/对数映射到控件量程 */
struct mixer_ctl *sw = mixer_get_ctl_by_name(mx, "Master Playback Switch");
mixer_ctl_set_value(sw, 0, mute ? 0 : 1); /* 0=静音, 1=正常 */
c
/* 方式二:应用层数字增益(无硬件音量控件时的兜底) */
/* 对 PCM 样本做缩放:sample *= gain(0.0~1.0);静音即 gain=0 */
| 控制 | 推荐实现 | 说明 |
|---|---|---|
| 音量 | 优先硬件 mixer(Master Playback Volume) |
零 CPU,不损动态范围 |
| 静音 | mixer Switch 或应用层 gain=0 | 说明书 4.5.3:启用后"关闭音频输入" |
说明书 4.5.3 备注"启用静音后将关闭音频输入"------这与本文"输入源切换 + 静音联动"一致:静音不仅压低输出,也可直接停掉采集以省资源。
五、与视频同出 HDMI:音视频同步
MEDAI-W2 最终要把视频(DRM 扫描,见《RGA+DRM》系列)与音频(ALSA 播放,本节)打包进同一根 HDMI。两端时钟天然不同源,需对齐:
- 主时钟选择 :直播/监控场景通常以音频时钟为基准(人耳对音频断续更敏感),视频按音频 PTS 对齐显示节奏;
- DRM vsync + ALSA 缓冲:视频按 VBlank 翻页(确定性),音频按 PCM 缓冲持续消费;二者以同一份归一化时间戳(见《FFmpeg 多协议归一》2.3 节微秒 PTS)调度;
- 抗漂移:周期性比对音/视频呈现时刻,必要时对视频做 1 帧重复/丢弃来追平,避免"嘴形对不上"。
六、与 Web 管理系统 / 说明书的映射
- 音频配置(说明书 4.5.3) :音量滑块 → 3.3 节 mixer 音量控件;静音开关 → 4.x 节 Switch/增益;音频输入源切换 → 2.3 节各 card/device 的
pcm_open切换; - 功能菜单(1.1 节):音频配置与解码设置并列,说明音频是独立于视频通道的一等公民;
- 系统监控(CPU 低位):Tinyalsa 直通模式下音频几乎不占 CPU(无 dmix/重采样),与画面侧卸载思路一致。
七、调试与验证
bash
# 1. 查看声卡与节点
cat /proc/asound/cards
ls -l /dev/snd/
# 2. 查看某 card 的 PCM 能力
tinypcminfo -D 0
# 3. 抓一段采集验证输入源(本地 mic/line-in 或 UVC UAC)
tinycap /tmp/test.wav -D 0 -d 0 -r 48000 -c 2 -b 16
# 4. 向 HDMI 播放验证输出
tinyplay /tmp/test.wav -D 0 -d <hdmi_device> -r 48000 -c 2 -b 16
# 5. 查看/设置 mixer(HDMI 使能、音量、静音)
tinymix # 列出全部控件
tinymix "IEC958 Playback Switch" 1
tinymix "Master Playback Volume" 80
| 现象 | 可能原因 | 排查手段 |
|---|---|---|
| HDMI 有画面没声音 | IEC958/HDMI 控件未开 或 采样率不匹配 | tinymix 确认开关;核对 Sink 支持的采样率 |
| 采集无数据 | 选错 card/device 或 UVC 未枚举 | cat /proc/asound/cards;UVC 插拔需重枚举 |
| 声音卡顿/爆音 | period 太小导致 XRUN | 调大 period_size,或 pcm_prepare 恢复 |
| 切换输入源后无声 | 旧 pcm 未关 / 新源未开 | 检查 2.3 节切换的 close+open 顺序 |
| 音画不同步 | 主时钟未统一 | 以音频时钟为基准对齐 PTS(见第五节) |
八、总结
MEDAI-W2 基于 RK3518 的音频链路,可以归纳为 "三源汇入、tinyalsa 直通、mixer 调控、随画同出":
- 三源汇入 :本地 Codec、UVC UAC、网络流音频三条输入,经
pcm_open选择/切换,汇入统一输出管线; - tinyalsa 直通:用轻量 Tinyalsa 直接操作 PCM 与 mixer,低延迟、确定性、省 CPU,契合嵌入式定点音频通路;
- mixer 调控 :音量(0~100%)走硬件
Master Playback Volume,静音走 Switch/增益,对应说明书 4.5.3 的 Web 控制; - 随画同出:HDMI 音频经 I2S→HDMI Codec DAI 送出,与视频(DRM 扫描)以同一份归一化 PTS 对齐,输出"有声画面"。
把音频侧的"采集 → 调控 → 输出"与画面侧的"解码 → 合成 → 显示"对齐,MEDAI-W2 才成为完整的音视频拉流解码器。这条 Tinyalsa/ALSA 链路同样适用于 RK35 系列(RK3518/RK3528/RK3568/RK3576)上的视频网关、会议终端与商业显示产品。
参考资料
- 《MEDAI-W2 拉流解码器使用说明书》(固件版本 2.1,文档版本 V1.0)
- 《MEDAI-W2 FFmpeg 多协议归一拉流》技术解析(同系列文章)
- 《MEDAI-W2 UVC 输入 × MPP 硬解码》技术解析(同系列文章)
- 《MEDAI-W2 RGA + DRM HDMI 输出》技术解析(同系列文章)
- ALSA Project:
Documentation/sound/;Tinyalsa(frameworks/base/media/tinyalsa)- Linux Kernel:
sound/soc/rockchip/、sound/usb/(UAC)- 瑞芯微 RK3518 平台技术资料(I2S / HDMI Audio / USB Audio 章节)