news 2026/5/22 18:13:10

Linux内核学习9--ALSA架构学习1(框架)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux内核学习9--ALSA架构学习1(框架)

1 ALSA框架

ALSA的全称其实是(Advanced Linux Sound Architecture),高级Linux声音架构。

没有看到太多合适的图,就先用一张ST的吧。

目前我的理解就是干了两个事。

2 驱动层

2.1 驱动层基本流程

驱动层将硬件封装成标准文件接口/dev/snd,提供了pcm和control两个接口。在这个部分的平台驱动中封装了I2S接口,DMA。Codec驱动了解码器,此外还有Controller。

DAPM 是 Dynamic Audio Power Management(动态音频电源管理) 的缩写,用于智能管理音频设备的电源状态,以优化功耗。

PCM DMAEngine 是一种结合了 PCM(脉冲编码调制)音频流 和 DMA(直接内存访问)引擎 的高效数据传输机制,用于在音频设备和内存之间直接传输音频数据,无需 CPU 频繁介入。

最后,当然是具体codec驱动的部分,也就是上图蓝色的部分。这部分我看内核本身就提供了非常多。

综上,这样一个播放的流程就是APP传数据到ALSA,然后ALSA启动DMA,硬件将音频数据传到I2S或者codec。最后ALSA通知app传输完毕。

有的设备DMA是在Soc之中,有的是在声卡上。不过树莓派的是soc里面。(3B一共10个通道)

tom@raspberrypi:~ $ ls /sys/class/dma dma0chan0 dma0chan1 dma0chan2 dma0chan3 dma0chan4 dma0chan5 dma0chan6 dma0chan7 dma0chan8 dma0chan9

2.2 树莓派3的封装

下面就是树莓派3B的封装。

tom@raspberrypi:~ $ ls /dev/snd/ by-path controlC0 controlC1 pcmC0D0p pcmC1D0p seq timer tom@raspberrypi:~ $ ls /dev/snd/by-path/ -l total 0 lrwxrwxrwx 1 root root 12 Apr 16 20:08 platform-3f00b840.mailbox -> ../controlC0 lrwxrwxrwx 1 root root 12 Apr 16 20:08 platform-3f902000.hdmi -> ../controlC1

其中controlC0是声卡0的控制通道,用于 mixer 控制、音量调节、开关设置等(供 amixer, alsamixer 使用)。

controlC1是声卡1的控制通道。

pcmC0D0p是声卡0的播放通道,表示C0=Card0,D0=Device0,p=Playback。

pcmC1D0p是声卡1的播放通道。

timer是做同步,seq是MIDI控制接口,这两个据说现在都很少用了。

声卡0和声卡1又是什么呢?查看两张卡的信息

tom@raspberrypi:~ $ cat /proc/asound/cards 0 [Headphones ]: bcm2835_headpho - bcm2835 Headphones bcm2835 Headphones 1 [vc4hdmi ]: vc4-hdmi - vc4-hdmi vc4-hdmi

可以看到分别是3.5MM接口和HDMI输出。

2.3 IOCTL的接口

驱动层中提供的ioctl接口可以简单通过strace看看。

tom@raspberrypi:~ $ strace -e ioctl aplay house_lo.wav ioctl(0, TCGETS, {c_iflag=ICRNL|IXON|IXANY|IUTF8, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHO|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0 ioctl(6, SIOCGIFINDEX, {ifr_name="wlan0", ifr_ifindex=3}) = 0 ioctl(0, TCGETS, {c_iflag=ICRNL|IXON|IXANY|IUTF8, c_oflag=NL0|CR0|TAB0|BS0|VT0|FF0|OPOST|ONLCR, c_cflag=B38400|CS8|CREAD, c_lflag=ISIG|ICANON|ECHO|ECHOE|ECHOK|IEXTEN|ECHOCTL|ECHOKE, ...}) = 0 Playing WAVE 'house_lo.wav' : Unsigned 8 bit, Rate 11025 Hz, Mono +++ exited with 0 +++

大概的接口如下:

控制接口(Control)
命令功能对应设备文件
SNDRV_CTL_IOCTL_CARD_INFO获取声卡信息controlC0
SNDRV_CTL_IOCTL_ELEM_READ读取混音器控件值(如音量)controlC0
SNDRV_CTL_IOCTL_ELEM_WRITE写入混音器控件值controlC0
PCM 设备接口
命令功能对应设备文件
SNDRV_PCM_IOCTL_INFO获取 PCM 设备信息pcmC0D0p
SNDRV_PCM_IOCTL_HW_PARAMS设置硬件参数(格式、采样率等)pcmC0D0p
SNDRV_PCM_IOCTL_PREPARE准备设备以开始播放/录制pcmC0D0p
SNDRV_PCM_IOCTL_WRITEI_FRAMES写入音频帧数据(播放)pcmC0D0p
SNDRV_PCM_IOCTL_READI_FRAMES读取音频帧数据(录制)pcmC0D0c

3 应用层

另外一件事就是在上层提供lib库以及相关工具。

3.1 ALSA-lib

头文件功能描述
<alsa/asoundlib.h>主头文件,包含所有常用功能的宏和类型定义。
<alsa/pcm.h>PCM(音频流)设备管理(播放/录制)。
<alsa/control.h>混音器(Mixer)和控件(如音量、开关)管理。
<alsa/seq.h>MIDI 序列器接口(用于音乐合成和事件调度)。
<alsa/rawmidi.h>原始 MIDI 设备访问。
<alsa/error.h>错误处理接口。

播放常见函数

函数作用
snd_pcm_open()打开 PCM 设备(如hw:0,0)。
snd_pcm_set_params()设置参数(格式、采样率、声道数、缓冲区大小等)。
snd_pcm_writei()/snd_pcm_readi()写入(播放)或读取(录制)交错(interleaved)格式的音频数据。
snd_pcm_prepare()准备设备以开始传输。
snd_pcm_drain()等待所有挂起的数据传输完成(优雅停止)。
snd_pcm_close()关闭设备。

控制常见函数

函数作用
snd_ctl_open()打开控制设备(如hw:0)。
snd_ctl_elem_list()列出所有可用控件(如 "Master Volume")。
snd_ctl_elem_get_value()获取控件当前值。
snd_ctl_elem_set_value()设置控件值。
snd_mixer_open()打开混音器接口(更高级的抽象)。

官方文档可以参考ALSA project - the C library reference: Index, Preamble and License

一个ALSA应用层例子

还是基于树莓派3B

sudo apt update sudo apt install libasound2-dev

代码

#include <stdio.h> #include <stdlib.h> #include <alsa/asoundlib.h> #define PCM_DEVICE "default" #define CONTROL_DEVICE "hw:0" // 声卡控制设备 int main(int argc, char *argv[]) { if (argc < 2) { printf("Usage: %s house_lo.wav\n", argv[0]); return 1; } // Open WAV file FILE *fp = fopen(argv[1], "rb"); if (!fp) { perror("fopen"); return 1; } // Skip WAV header (44 bytes for standard PCM WAV) fseek(fp, 44, SEEK_SET); // Open control interface snd_mixer_t *mixer; snd_mixer_selem_id_t *sid; static const char *selem_name = "PCM"; snd_mixer_open(&mixer, 0); snd_mixer_attach(mixer, CONTROL_DEVICE); snd_mixer_selem_register(mixer, NULL, NULL); snd_mixer_load(mixer); snd_mixer_selem_id_malloc(&sid); snd_mixer_selem_id_set_index(sid, 0); snd_mixer_selem_id_set_name(sid, selem_name); snd_mixer_elem_t* elem = snd_mixer_find_selem(mixer, sid); if (elem) { long minv, maxv; snd_mixer_selem_get_playback_volume_range(elem, &minv, &maxv); snd_mixer_selem_set_playback_volume_all(elem, (maxv * 70) / 100); // 设置 70% 音量 printf("Volume set to 70%%\n"); } // Setup PCM device snd_pcm_t *pcm; snd_pcm_hw_params_t *params; snd_pcm_open(&pcm, PCM_DEVICE, SND_PCM_STREAM_PLAYBACK, 0); snd_pcm_hw_params_malloc(&params); snd_pcm_hw_params_any(pcm, params); snd_pcm_hw_params_set_access(pcm, params, SND_PCM_ACCESS_RW_INTERLEAVED); snd_pcm_hw_params_set_format(pcm, params, SND_PCM_FORMAT_S16_LE); snd_pcm_hw_params_set_channels(pcm, params, 2); unsigned int rate = 44100; snd_pcm_hw_params_set_rate_near(pcm, params, &rate, 0); snd_pcm_hw_params(pcm, params); // Playback loop int frames; char buf[4096]; while (!feof(fp)) { size_t read = fread(buf, 1, sizeof(buf), fp); if (read > 0) { frames = snd_pcm_writei(pcm, buf, read / 4); // 2 bytes/sample * 2 channels if (frames < 0) snd_pcm_prepare(pcm); } } // Cleanup snd_pcm_drain(pcm); snd_pcm_close(pcm); fclose(fp); snd_mixer_close(mixer); snd_mixer_selem_id_free(sid); return 0; }

音源这里还是用之前I2S那篇文章的house_lo.wav。总线学习5--I2S_max98357接喇叭教程-CSDN博客

不过要先把文件转成44100 Hz,双声道16bit。

原始是11025 Hz,单声道8bit。

tom@raspberrypi:~/alsa $ ffprobe house_lo.wav ffprobe version 5.1.6-0+deb12u1+rpt1 Copyright (c) 2007-2024 the FFmpeg developers built with gcc 12 (Debian 12.2.0-14) configuration: --prefix=/usr --extra-version=0+deb12u1+rpt1 --toolchain=hardened --incdir=/usr/include/aarch64-linux-gnu --enable-gpl --disable-stripping --disable-mmal --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libdav1d --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libglslang --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librabbitmq --enable-librist --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libssh --enable-libsvtav1 --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzimg --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-sand --enable-sdl2 --disable-sndio --enable-libjxl --enable-neon --enable-v4l2-request --enable-libudev --enable-epoxy --libdir=/usr/lib/aarch64-linux-gnu --arch=arm64 --enable-pocketsphinx --enable-librsvg --enable-libdc1394 --enable-libdrm --enable-vout-drm --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libx264 --enable-libplacebo --enable-librav1e --enable-shared libavutil 57. 28.100 / 57. 28.100 libavcodec 59. 37.100 / 59. 37.100 libavformat 59. 27.100 / 59. 27.100 libavdevice 59. 7.100 / 59. 7.100 libavfilter 8. 44.100 / 8. 44.100 libswscale 6. 7.100 / 6. 7.100 libswresample 4. 7.100 / 4. 7.100 libpostproc 56. 6.100 / 56. 6.100 Input #0, wav, from 'house_lo.wav': Metadata: date : 1999-11-04 IENG : Deepz0ne encoder : Sound Forge 4.5 Duration: 00:00:07.10, bitrate: 88 kb/s Stream #0:0: Audio: pcm_u8 ([1][0][0][0] / 0x0001), 11025 Hz, 1 channels, u8, 88 kb/s

转换:

ffmpeg -i house_lo.wav -ar 44100 -ac 2 -sample_fmt s16 house_lo_fixed.wav

之后就可以播放了。

tom@raspberrypi:~/alsa $ ./alsa_play_control house_lo_fixed.wav Volume set to 70%

3.2 ALSA-utils

提供的工具如下:

工具名称功能描述
aplay播放音频文件(WAV、RAW 等格式)。
arecord录制音频到文件(支持多种格式和参数配置)。
alsamixer基于终端的交互式混音器,用于调节音量、选择输入/输出设备等。
amixer命令行混音器控制工具(脚本友好,可编程调节音量、静音等)。
speaker-test测试扬声器或耳机(生成白噪声、正弦波等测试音)。
iecset配置 IEC958(S/PDIF)数字音频接口(如光纤/同轴输出)。
alsactl保存和加载声卡配置(如音量设置到/etc/asound.state)。
aconnectMIDI 设备连接管理(用于音乐合成器或 MIDI 控制器)。

使用场景如下:

普通用户:用 alsamixer 调节音量。

开发者:通过 amixer 脚本化控制音频设备。

调试:aplay/arecord 和 speaker-test 快速验证硬件状态。

speaker-test好像放的杂音居多。

4 ALSA和tinyalsa

tinyalsa最近也是经常看到,这里稍微做一下对比。

特性ALSA-libTinyALSA
开发背景ALSA 官方维护,功能全面且复杂。Android 团队为嵌入式优化,轻量级简化版。
代码体积较大(完整功能库)极小(仅核心功能)
功能覆盖支持 PCM、Mixer、MIDI、定时器等完整功能。仅支持 PCM 和基础 Mixer 控制。
依赖关系依赖 Linux 内核 ALSA 驱动。仍依赖 ALSA 驱动,但接口更简化。
适用场景桌面/服务器等通用 Linux 系统。嵌入式设备(如 Android 电视、IoT)。
API 复杂度高(提供多层次抽象)。低(直接操作设备文件)。

据说用tinyalsa还有一个原因是功耗问题。alsa框架因为功能复杂,导致功耗要高一些。

5 参考

高通msm8996平台的ASOC音频路径分析 - xtusir - 博客园

瑞芯微-I2S | 音频驱动调试基本命令和工具-基于rk3568_rk3568 i2s-CSDN博客

高通音频架构(三)_adsp-CSDN博客

瑞芯微-I2S | 音频驱动调试基本命令和工具-基于rk3568-2

ALSA project - the C library reference: Index, Preamble and License

学习的方法(来自GPT)

在学习和实践 ALSA 时,以下是一些具体的项目示例,这些项目涵盖了不同层次的开发,从简单的应用程序到较为复杂的驱动开发,帮助你更好地理解和掌握 ALSA。

### 1. **简单 PCM 音频播放器**
- **目标**: 开发一个简单的 PCM 音频播放器,能够播放 `.wav` 格式的音频文件。
- **技术点**: 使用 `libasound` API 打开音频设备,设置 PCM 参数(如采样率、声道数、位深等),读取音频文件数据并输出到音频设备。
- **扩展**: 添加音量控制、暂停和继续播放功能,支持其他音频格式(如 `.mp3`)。

### 2. **音频录音程序**
- **目标**: 开发一个简单的音频录音程序,能够录制来自麦克风的音频并保存为 `.wav` 文件。
- **技术点**: 使用 ALSA API 打开录音设备,设置录音参数,读取音频数据并保存到文件。
- **扩展**: 添加实时音频监控功能,支持不同的音频编码格式(如 `.flac`),实现音频压缩功能。

### 3. **自定义 ALSA 混音器控制**
- **目标**: 开发一个自定义的 ALSA 混音器控制工具,可以调节音频设备的音量、增益、平衡等。
- **技术点**: 使用 ALSA 控制接口 API(如 `snd_mixer_open`、`snd_mixer_selem_register` 等)来访问和操作音频设备的混音器控件。
- **扩展**: 实现 GUI 版的混音器控制工具,支持保存和恢复混音器设置的配置文件。

### 4. **定制音频驱动程序**
- **目标**: 开发一个简单的 ALSA 驱动程序,用于控制一个虚拟或简单的音频硬件设备。
- **技术点**: 学习如何编写一个基本的 PCM 驱动程序,理解 ALSA 内核 API(如 `snd_pcm_new`、`snd_pcm_ops` 等),处理音频数据的 DMA 传输。
- **扩展**: 支持更复杂的硬件设备,如具有多个 PCM 子设备的音频控制器,实现高级功能,如音频格式转换、硬件加速等。

### 5. **基于 I2S 的嵌入式音频项目**
- **目标**: 在嵌入式设备(如 Raspberry Pi 或 BeagleBone)上,使用 I2S 接口与外部 DAC(数模转换器)或 ADC(模数转换器)通讯,实现音频输入和输出功能。
- **技术点**: 配置设备树中的 I2S 接口,编写或修改 ALSA 驱动以支持 I2S,处理音频数据的采集与播放。
- **扩展**: 开发一个简单的 DSP(数字信号处理)功能,如均衡器或混响效果。

### 6. **音频流处理器**
- **目标**: 开发一个实时音频流处理器,能够接收音频输入,进行处理(如滤波、音效),然后输出到音频设备或网络。
- **技术点**: 学习如何高效地处理实时音频流,使用多线程技术来并行处理音频数据,使用 ALSA 和网络 API 来管理输入和输出。
- **扩展**: 实现跨网络的音频传输和同步,支持多个音频流的混合处理。

### 7. **多声道音频系统**
- **目标**: 构建一个多声道(如 5.1 或 7.1 声道)音频播放系统,支持多声道音频文件的播放和音频设备的配置。
- **技术点**: 使用 ALSA API 来配置多声道 PCM 设备,处理多声道音频文件的解析和播放,管理不同声道的音量和平衡。
- **扩展**: 实现多声道音频的虚拟化处理,如虚拟环绕声效果,支持动态声道配置。

### 8. **音频诊断和测试工具**
- **目标**: 开发一个音频诊断工具,用于检测和分析音频设备的性能和质量。
- **技术点**: 使用 ALSA API 进行音频设备的配置和测试,生成和分析音频信号(如正弦波、方波),测量延迟、抖动等性能参数。
- **扩展**: 实现自动化的音频设备测试流程,生成详细的报告,支持多种音频格式和设备类型的测试。

### 9. **嵌入式音频处理系统**
- **目标**: 在嵌入式系统(如树莓派)上开发一个复杂的音频处理系统,实现音频采集、处理、混音和播放的全流程。
- **技术点**: 结合 ALSA 和 DSP 技术,处理实时音频流,包括采样率转换、音频增强、动态范围控制等。
- **扩展**: 实现对网络音频流的支持,开发音频效果插件,优化系统性能以支持低延迟的音频处理。

### 10. **定制音乐播放器**
- **目标**: 开发一个定制的音乐播放器,支持播放本地音频文件、在线流媒体,并提供自定义的用户界面。
- **技术点**: 使用 ALSA 进行音频输出,结合其他库(如 libmpg123、FFmpeg)解析和解码音频文件,实现播放列表管理、音效处理等功能。
- **扩展**: 支持多种音频格式,添加均衡器、音频可视化效果,集成网络电台或流媒体服务。

### 总结
这些项目覆盖了 ALSA 的各个方面,从用户空间的简单应用开发,到内核空间的驱动程序编写,再到嵌入式系统的音频处理。通过完成这些项目,你将深入理解 ALSA 的工作原理,并掌握开发高效、稳定音频应用和驱动程序的技能。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/22 18:10:42

ops-transformer 仓库核心能力解析:FlashAttention 在昇腾 NPU 上的融合实现

ops-transformer 是昇腾 CANN 算子生态中&#xff0c;专门面向 Transformer 架构优化的高性能算子仓库。它的核心价值在于把大模型训练中计算最密集的几个算子做到了昇腾 NPU 上的极致性能&#xff0c;而这个极致性能的实现方式&#xff0c;依赖的是 CANN 架构中 GE 图引擎的算…

作者头像 李华
网站建设 2026/5/22 18:08:00

XGBoost机器学习库终极指南:从入门到精通的完整教程

XGBoost机器学习库终极指南&#xff1a;从入门到精通的完整教程 【免费下载链接】xgboost Scalable, Portable and Distributed Gradient Boosting (GBDT, GBRT or GBM) Library, for Python, R, Java, Scala, C and more. Runs on single machine, Hadoop, Spark, Dask, Flink…

作者头像 李华
网站建设 2026/5/22 18:08:00

终极OpenProject开发环境搭建指南:3小时从零到部署的完整攻略

终极OpenProject开发环境搭建指南&#xff1a;3小时从零到部署的完整攻略 【免费下载链接】openproject OpenProject is the leading open source project management software. 项目地址: https://gitcode.com/GitHub_Trending/op/openproject 还在为跨平台开发环境配置…

作者头像 李华
网站建设 2026/5/22 18:07:02

2026论文降AIGC网站:11款工具实测谁才是真神器?

2026 年学术审核标准持续收紧&#xff0c;论文重复率、AIGC 检出率已经成为毕业答辩、期刊投稿的硬性门槛。随着知网、维普、Turnitin 等主流检测平台算法不断优化升级&#xff0c;对论文原创性和人工写作痕迹的要求愈发严格。面对日益严苛的审查机制&#xff0c;越来越多学生和…

作者头像 李华
网站建设 2026/5/22 18:06:02

阿里云MaaS业务Token收入5个月增15倍,Qwen 3.7 Max发力Coding领域

阿里云MaaS业务Token收入增长显著阿里云在5月20日的发布会上透露&#xff0c;阿里云MaaS业务的Token收入在2026年的过去5个月里增长了15倍&#xff0c;月度Token收入已达数亿元级别。拉动这笔收入的直接原因是Agent。为何急于发布新模型&#xff1f;这一天&#xff0c;阿里云发…

作者头像 李华
网站建设 2026/5/22 18:03:49

大学生班级|基于SprinBoot+vue的大学生班级管理系统(源码+数据库+文档)

大学生班级管理系统 基于SprinBootvue的大学生班级管理系统 一、前言 二、系统设计 三、系统功能设计 系统功能实现 后台模块实现 管理员功能实现 教师功能实现 学生功能实现 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取…

作者头像 李华