Linux ALSA 之五:ALSA Proc Info

article/2025/10/3 2:55:59

ALSA Proc Info

  • 一、概述
  • 二、Proc Files of Alsa Driver
    • 1、/proc/asound/xxx 简述
    • 2、创建 /proc/asound 目录树
      • 2.1 /proc/asound/version 文件
      • 2.2 /proc/asound/devices 文件
      • 2.3 /proc/asound/cards 文件
      • 2.4 /proc/asound/cardx 目录
      • 2.5 /proc/asound/pcm 文件

一、概述

Linux系统上的 /proc 目录是一种文件系统,即 proc文件系统。与其它常见的文件系统不同的是,/proc是一种伪文件系统(也即虚拟文件系统),存储的是当前内核运行状态的一系列特殊文件,用户可以通过这些文件查看有关系统硬件及当前正在运行进程的信息,甚至可以通过更改其中某些文件来改变内核的运行状态。

基于 /proc 文件系统如上所述的特殊性,其内的文件也常被称作虚拟文件,并具有一些独特的特点。例如,其中有些文件虽然使用查看命令查看时会返回大量信息,但文件本身的大小却会显示为0字节。此外,这些特殊文件中大多数文件的时间及日期属性通常为当前系统时间和日期,这跟它们随时会被刷新(存储于RAM中)有关。

其中 ALSA 有自己的 proc tree,/proc/asound. 在这个目录下可以找到许多关于
nd card 的详细信息。

二、Proc Files of Alsa Driver

该节主要用于讲解在 alsa core 中创建的 /proc/asound 目录树以及如何实现的。(以下截图中显示的 card 详细信息均以 mstar alsa 为例)

1、/proc/asound/xxx 简述

在 /proc/asound 下执行 'ls -l' 可以看到在 sound proc 目录下涉及的信息如下:
在这里插入图片描述
其中主要的节点如下:

  • cardx 本机当前注册的 sound card;
  • cards 显示当前配置的 Alsa Drivers,index,the id string,short and long descriptions;
  • version 显示版本字符串;
  • devices 列举本机设备映射;
  • pcm 列举当前可用的 pcm devides,格式如下:<card>-<device>: <id>: <name> : <sub-streams>

2、创建 /proc/asound 目录树

在 sound.c alsa_sound_init() 中会 call snd_info_init() 函数创建 /proc/asound dir,并将该 entry 保存在全局变量 snd_proc_root(即作为 sound proc root entry),代码如下:

int __init snd_info_init(void)
{//1、创建 alsa proc root entry;snd_proc_root = snd_info_create_entry("asound", NULL);	if (!snd_proc_root)return -ENOMEM;snd_proc_root->mode = S_IFDIR | 0555;//2、创建 dir: /proc/asoundsnd_proc_root->p = proc_mkdir("asound", NULL);	if (!snd_proc_root->p)goto error;
#ifdef CONFIG_SND_OSSEMULsnd_oss_root = create_subdir(THIS_MODULE, "oss");if (!snd_oss_root)goto error;
#endif
#if IS_ENABLED(CONFIG_SND_SEQUENCER)snd_seq_root = create_subdir(THIS_MODULE, "seq");if (!snd_seq_root)goto error;
#endifif (snd_info_version_init() < 0 ||	//3、创建 file: /proc/asound/versionsnd_minor_info_init() < 0 ||	//4、创建 file: /proc/asound/devicessnd_minor_info_oss_init() < 0 ||snd_card_info_init() < 0 ||		//5、创建 file: /proc/asound/cardssnd_info_minor_register() < 0)goto error;return 0;error:snd_info_free_entry(snd_proc_root);return -ENOMEM;
}

2.1 /proc/asound/version 文件

如上代码所示,在 snd_info_init() 函数中除了创建 /proc/asound dir 时,紧接着在 snd_proc_root entry 下(即以 snd_proc_root enter 作为 parent entry) 创建 “version” 文件(即 /proc/asound/version),并提供了 read() 方法,代码详解略,cat /proc/asound/version 如下:
在这里插入图片描述

2.2 /proc/asound/devices 文件

接着在 snd_proc_root entry 下创建 “devices” 文件(即 /proc/asound/devices),提供了 read() 方法,cat /proc/asound/devices 如下:
在这里插入图片描述
对于 devices 的 print 格式如下:

  • control “minor: [card_id] : control”
  • pcm “minor: [card_id- device_id]: digital audio playback/capture”
  • timer “minor: : timer”

2.3 /proc/asound/cards 文件

接着在 snd_proc_root entry 下创建 “cards” 文件(即 /proc/asound/cards),提供了 read() 方法,cat /proc/asound/cards 如下:
在这里插入图片描述
对于 cards 的 print 格式如下:

card_id [card_id_string	]:	card_driver - card_shortnamecard_longname

2.4 /proc/asound/cardx 目录

我们都知道在 alsa driver 开始的时候需要调用 snd_card_new() 创建声卡 card,与此同时也会调用 sound/core/info.c snd_info_card_create() 函数在 snd_proc_root 下创建 “cardx” dir(即 /proc/asound/cardx),并将对应的 entry 保存在 card->proc_root,以便后面基于该声卡的 snd device 等节点均以其作为 parent entry,snd_info_card_create() 函数如下:

/** create a card proc file* called from init.c*/
int snd_info_card_create(struct snd_card *card)
{char str[8];struct snd_info_entry *entry;if (snd_BUG_ON(!card))return -ENXIO;sprintf(str, "card%i", card->number);entry = create_subdir(card->module, str);	//创建 card%i dirif (!entry)return -ENOMEM;card->proc_root = entry;	//保存 card entryreturn 0;
}

在 cardx dir 下主要会对每个 pcm device 创建对应的 pcmxp/c dir,创建方式如下:
我们都知道在 alsa driver 中创建 pcm device 时都需要调用 snd_pcm_new() 函数,在该函数中也分别会对 Playback & Capture 调用 snd_pcm_new_stream(PLAYBACK/CAPTURE) 定义 playback & capture dev name,然后则会调用 snd_pcm_stream_proc_init() 函数,在该函数中会在 card->proc_root entry 下创建 pcmxp/c dir(即 /proc/asound/cardx/pcmxp | pcmxc),并将对应的 entry 保存在 pcm->streams[PLAYBACK/CAPTURE]->proc_root;同时也会在 pcm->streams[]->proc_root 下创建 info 文件(即 /proc/asound/cardx/pcmxp|c/info),并提供 read() 方法,代码如下:

static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr)
{struct snd_pcm *pcm = pstr->pcm;struct snd_info_entry *entry;char name[16];// 创建 pcmxp/c dirsprintf(name, "pcm%i%c", pcm->device, pstr->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c');entry = snd_info_create_card_entry(pcm->card, name,pcm->card->proc_root);if (!entry)return -ENOMEM;entry->mode = S_IFDIR | 0555;if (snd_info_register(entry) < 0) {snd_info_free_entry(entry);return -ENOMEM;}pstr->proc_root = entry;// 在 pcmxp|c dir 下创建 info 文件entry = snd_info_create_card_entry(pcm->card, "info", pstr->proc_root);if (entry) {snd_info_set_text_ops(entry, pstr, snd_pcm_stream_proc_info_read);if (snd_info_register(entry) < 0) {snd_info_free_entry(entry);entry = NULL;}}pstr->proc_info_entry = entry;return 0;
}

经过上述创建 dir 以及 cat /proc/asound/cardx/pcmxp|c/info 如下所示(其中涉及 pcmxp|c/info read 详细参数看 Code):
在这里插入图片描述
由前面学习知道对于 pcm 播放的最小单元是 substream,故接着在 snd_pcm_new_stream() 会对该 pcm playback/capture stream 下所有的 substreams (substream_count 一般都是 1)调用 snd_pcm_substream_proc_init() 函数,即在 pcm->streams[]->proc root 下创建 subx dir(即 /proc/asound/cardx/pcmxp|c/sub0),并将对应的 entry 保存在 pcm->streams[]->substream[0]->proc_root;同时会在 pcm->streams[]->substream[0]->proc_root 下创建 info,hw_params,sw_params,status 文件(即 /proc/asound/cardx/pcmxp|c/pcmxp|c/sub0/info | hw_params |sw_params | status),并提供 read() 方法,分别执行 cat 后如下:
在这里插入图片描述
**Note:**如上所示,对于 hw_params & sw_params & status 由于均用到了 runtime,故只有在播放的时候才能 print info.

特别地,在 alsa 驱动中当需要为 pcm dma 分配内存 allocate pages 时(即有调用 snd_pcm_lib_preallocate_pages_for_all(size,max))时,则会在 pcm->streams[]->substream[0]->proc_root 下创建 prealloc、prealloc_max 文件(即 /proc/asound/cardx/pcmxp|c/sub0/prealloc | prealloc_max),并提供 read() [all] & write() [only for prealloc] 方法,代码如下:

static inline void preallocate_info_init(struct snd_pcm_substream *substream)
{struct snd_info_entry *entry;if ((entry = snd_info_create_card_entry(substream->pcm->card, "prealloc", substream->proc_root)) != NULL) {entry->c.text.read = snd_pcm_lib_preallocate_proc_read;entry->c.text.write = snd_pcm_lib_preallocate_proc_write;entry->mode |= 0200;entry->private_data = substream;if (snd_info_register(entry) < 0) {snd_info_free_entry(entry);entry = NULL;}}substream->proc_prealloc_entry = entry;if ((entry = snd_info_create_card_entry(substream->pcm->card, "prealloc_max", substream->proc_root)) != NULL) {entry->c.text.read = snd_pcm_lib_preallocate_max_proc_read;entry->private_data = substream;if (snd_info_register(entry) < 0) {snd_info_free_entry(entry);entry = NULL;}}substream->proc_prealloc_max_entry = entry;
}

对该节点执行 cat & echo 如下(详细略):
在这里插入图片描述

2.5 /proc/asound/pcm 文件

在 core/pcm.c 下 alsa_pcm_info() 中会调用 snd_pcm_proc_init() 函数,即会在 snd_proc_root 下创建 pcm 文件(即 /proc/asound/pcm),并提供 read() 方法,代码如下(详细描述略):

/**  Info interface*/static void snd_pcm_proc_read(struct snd_info_entry *entry,struct snd_info_buffer *buffer)
{struct snd_pcm *pcm;mutex_lock(&register_mutex);list_for_each_entry(pcm, &snd_pcm_devices, list) {snd_iprintf(buffer, "%02i-%02i: %s : %s",pcm->card->number, pcm->device, pcm->id, pcm->name);if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)snd_iprintf(buffer, " : playback %i",pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count);if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream)snd_iprintf(buffer, " : capture %i",pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count);snd_iprintf(buffer, "\n");}mutex_unlock(&register_mutex);
}static struct snd_info_entry *snd_pcm_proc_entry;static void snd_pcm_proc_init(void)
{struct snd_info_entry *entry;entry = snd_info_create_module_entry(THIS_MODULE, "pcm", NULL);if (entry) {snd_info_set_text_ops(entry, NULL, snd_pcm_proc_read);if (snd_info_register(entry) < 0) {snd_info_free_entry(entry);entry = NULL;}}snd_pcm_proc_entry = entry;
}

执行 cat /proc/asound/pcm 后如下:
在这里插入图片描述
**Note:**其中对于 dai 来说,pcm->id 为如下:
在这里插入图片描述
pcm->name 则需要在 alsa driver 中手动去赋值。
该 read() 函数会列出所有 snd_pcm 下的 info 信息(在 snd_pcm_dev_register() 中会将所有的 snd_pcm 添加到 snd_pcm_devices list 中)

特别地,对于 alsa asoc 中涉及的 dai 对应的节点会类似如下(详细解析见后面章节):
在这里插入图片描述
在这里插入图片描述
特殊,在使用 audio driver 时还可以通过 CONFIG_SND_DEBUG=y && CONFIG_SND_PROC_FS=y 宏隔开在 alsa driver 中自己实现 proc 操作,如 dummy.c => dummy_proc_init/write/read() 用来 print/change dummy->pcm_hw_params(详细略)。


http://chatgpt.dhexx.cn/article/xXgA5pRF.shtml

相关文章

Linux ALSA 之二:ALSA 声卡与设备

ALSA 声卡与设备 一、ALSA Sound 初始化1、alsa_sound_init() 入口函数2、init_soundcore() 入口函数 二、声卡结构体与创建、注册1、struct snd_card2、声卡创建流程3、声卡创建过程使用举例 三、声卡之 Pcm 设备1、Pcm 设备简介2、ALSA Driver 的 Pcm 中间层3、Pcm 设备创建 …

ALSA音频编程

一、前序 这里了解一下各个参数的含义以及一些基本概念。 声音是连续模拟量&#xff0c;计算机将它离散化之后用数字表示&#xff0c;就有了以下几个名词术语。 样本长度(sample)&#xff1a;样本是记录音频数据最基本的单位&#xff0c;计算机对每个通道采样量化时数字比特…

alsa 驱动介绍

Machine 以装配有CS4270的一款android 智能电视的为例 /sound/soc/samsung/exynos.c Platform 以Samsung cpu exynos4412为例 /sound/soc/samsung/ Codec 以wolfson的Codec芯片cs4270为例 /sound/soc/codecs/cs4270.c ALSA 框架介绍 Alsa 太多太杂&#xff0c;很难整理的规整&a…

ALSA Configure

0. 前言 本文主要介绍alsa-lib配置文件相关代码的分析内容。 1. 配置文件的路径 在alsa-lib中&#xff0c;函数 snd_config_topdir 用于获取配置文件的路径&#xff0c;有两个方法可以进行配置&#xff1a; 使用环境变量 ALSA_CONFIG_DIR 进行配置。在生成configure时&…

ALSA应用层编程播放音乐

关于ALSA&#xff0c;网上也有介绍&#xff0c;但是我在看的时候看的也是一脸懵逼&#xff0c;不是介绍的不好&#xff0c;是因为我之前对于嵌入式软件这一块实在没什么了解&#xff0c;之前一直学的JAVA&#xff0c;整个体系跟JAVA还是有很大的区别&#xff0c;要学的也完全是…

ALSA系统简析

一 音频架构 如图所示 是 嵌入式系统的音频连接 音频编解码器将数字音频信号 转换成 扬声器播放所需要的模拟声音信号。而通过麦克风时&#xff0c;则执行相反的过程。 数字音频信号通过 PCM技术对模拟信号以某个比特率采样得到的&#xff0c;编解码器的任务就是以支持的PCM…

ALSA编程精华

https://www.cnblogs.com/cslunatic/p/3677729.html 一、前序 这里了解一下各个参数的含义以及一些基本概念。 声音是连续模拟量&#xff0c;计算机将它离散化之后用数字表示&#xff0c;就有了以下几个名词术语。 样本长度(sample)&#xff1a;样本是记录音频数据最基本的…

ALSA学习笔记

文章目录 一、概述二、系统架构三、常用操作命令1、安装ALSA2、查看音频设备3、列出音频设备4、音量控制器 四、常见问题1、cannot open mixer: 没有那个文件或目录 一、概述 ALSA&#xff08;Advanced Linux Sound Architecture&#xff09;&#xff0c;高级Linux声音架构的简…

音频ALSA架构简介

一、ALSA架构 ALSA&#xff08;Advanced Linux Sound Architecture&#xff09;即高级 Linux 声音架构。 嵌入式移动设备的音频子系统目前主要是ALSA 驱动 asoc 框架&#xff0c;其中包括 codec driver、 platform driver、 machine driver 等。 codec driver只关心 codec 本身…

Linux ALSA 之一:ALSA 架构简介

一、概述 ALSA是 Advanced Linux Sound Architecture 的缩写&#xff0c;目前已经成为了linux的主流音频体系结构。 在 Linux 内核设备驱动层&#xff0c;ALSA 提供了 alsa-driver&#xff0c;在应用层&#xff0c;ALSA 为我们提供了 alsa-lib&#xff0c;故在其支持下&#…

ALSA (高级Linux声音架构)、ASOC基础知识

目录 第一节&#xff1a;什么是ALSA和ASOC 第二节&#xff1a;ALSA框架 第三节&#xff1a;ALSA的使用 第四节&#xff1a;ASOC的硬件框架 第四节&#xff1a;ASOC的软件框架 第一节&#xff1a;什么是ALSA和ASOC ALSA是Advanced Linux Sound Architecture&#xff0c;高级…

动态链接库dlopen的函数的使用

转自&#xff1a;http://blog.const.net.cn/a/17154.htm 编译时候要加入 -ldl (指定dl库) dlopen 基本定义 功能&#xff1a;打开一个动态链接库 [喝小酒的网摘]http://blog.const.net.cn/a/17154.htm 包含头文件&#xff1a; #include <dlfcn.h> 函数定义&#xff…

dlopen的用法

1、前言 为了使程序方便扩展&#xff0c;具备通用性&#xff0c;可以采用插件形式。采用异步事件驱动模型&#xff0c;保证主程序逻辑不变&#xff0c;将各个业务已动态链接库的形式加载进来&#xff0c;这就是所谓的插件。linux提供了加载和处理动态链接库的系统调用&#xff…

织梦上一篇下一篇没有了改为英文

织梦上一篇下一篇没有了改为英文 网站根目录找到 include/arc.archives.class.php 文件 打开找到 上一篇改为 Previous上一篇后面的“没有了” 改为 No Previous原图修改后 接着放下翻&#xff0c;紧贴着下面的“下一篇&#xff0c;没有了” 找到 下一篇改为 在这里插入…

在wordpress文章页中显示上一篇和下一篇文章

查看原文&#xff1a;http://www.hellonet8.com/1162.html 今天博主在看别人博客的时候发现他们的文章末尾会有显示上一篇和下一篇的文章链接&#xff0c;所以也想在自己的博客中添加这个功能。这么做顺便可以增加文章之间的相关性&#xff0c;对搜索引擎的蜘蛛也会友好些。废话…

js 实现 点击上一篇、下一篇功能

列表界面&#xff1a; 详细界面&#xff1a; 思路&#xff1a; 1. 首先目录列表渲染的数据是通过接口调用取到的值&#xff0c;然后点击具体某一条数据的时候&#xff0c;获取到他的 ID&#xff0c;然后通过路由跳转的时候带到详细信息页面。 2. 在详细页面中&#xff0c;先再…

Vue中 实现上一篇下一篇的功能

效果&#xff1a; 看下html页面 <div class"NewsDetails_cont_footer"><!-- 使用三目运算符判断 按钮是否可以点击 --><div click"last" :class"lastNoShow ? noClick : btn"><img src"../assets/img/newsDetail/公共…

java实现上一篇下一篇功能

根据文章类型查询&#xff0c;实现上一篇、下一篇的效果 自定义实体Dto(这里只放出扩展字段) Getter Setter public class OsArticleDto extends BaseDto {/** */private static final long serialVersionUID 1L;/** 上一篇文章id*/private String beforeId;/*** 上一篇文章…

vue实现上一篇下一篇

先来看一下效果图 请求回来所有文章&#xff0c;根据索引进行上一篇下一篇的判断 首先为两个按钮绑定点击事件 <buttonclick"last(lastId, columnId)":disabled"isLast":class"{ disClick: isLast true }">上一篇:{{ lastTitle }}</b…

Django针对上一篇和下一篇文章标题的实现逻辑

1、要求显示效果 2、前端html内容 <div><nav aria-label"..."><ul class"pager"><li><a href"/blog/detail/{{ previous_article.article_id }}">上一篇&#xff1a;{{ previous_article.title }}</a><…