Linux ALSA 之五 ALSA Proc Info

news2025/2/25 11:03:05

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/asound
	snd_proc_root->p = proc_mkdir("asound", NULL);	
	if (!snd_proc_root->p)
		goto error;
#ifdef CONFIG_SND_OSSEMUL
	snd_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;
#endif
	if (snd_info_version_init() < 0 ||	//3、创建 file: /proc/asound/version
	    snd_minor_info_init() < 0 ||	//4、创建 file: /proc/asound/devices
	    snd_minor_info_oss_init() < 0 ||
	    snd_card_info_init() < 0 ||		//5、创建 file: /proc/asound/cards
	    snd_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_shortname
							card_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 dir
	if (!entry)
		return -ENOMEM;
	card->proc_root = entry;	//保存 card entry
	return 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 dir
	sprintf(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://www.coloradmin.cn/o/151545.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

以“辛”为鉴,直播电商如何“知兴替”?

直播电商行业近年来创造了一个又一个销售神话。辛选2022年双11期间&#xff0c;18场直播销售额破亿。罗永浩在淘宝的首秀&#xff0c;6小时带货2亿元。直播间内外似乎一片繁华&#xff0c;但与此同时&#xff0c;也有许多曾经创造了带货奇迹的主播被市场淘汰&#xff0c;淡出视…

【笔记:第2课】学习开发一个RISC-V上的操作系统 - 汪辰 - 2021春

文章目录前言来源正文小结前言 创作开始时间&#xff1a;2023年1月9日20:11:06 如题&#xff0c;学习一下RISC-V。 来源 https://www.bilibili.com/video/BV1Q5411w7z5?p2&vd_source73a25632b4f745be6bbcfe3c82bb7ec0 正文 计算机硬件组成&#xff1a; 总线CPU&…

迷宫问题 | 深度优先

目录 一、说明 二、步骤 三、代码 四、结果 一、说明 什么是深度优先&#xff1f; DFS即Depth First Search&#xff0c;深度优先搜索属于图算法的一种&#xff0c;是一个针对图和树的遍历算法&#xff0c;利用深度优先搜索算法可以产生目标图的相应拓扑排序表&#xff0c…

身兼数据科学家和自由职业者,算算我在2022赚了多少钱?

2022年,我作为自由职业者数据科学家赚了多少钱&#xff1f;长按关注《Python学研大本营》&#xff0c;加入读者群&#xff0c;分享更多精彩扫码关注《Python学研大本营》&#xff0c;加入读者群&#xff0c;分享更多精彩大家好&#xff0c;首先&#xff0c;我已经等了很久了。2…

保姆级 | 最新Burpsuite安装配置

文章目录 0x00 前言 0x01 环境说明 0x02 准备工作 0x03 安装JDK 0x04 配置JDK环境 0x05 Burpsuite安装 0x06 Burpsuite环境配置 0x07 Burpsuite设置代理 0x08 Burpsuite使用验证 0x09 总结 0x00 前言 Burp Suite 是用于攻击 web 应用程序的集成平台&#xff0c;包含了…

mongodb 中做 join 的方法

【问题】Imagine you have a collection for posts, and each of these posts has the attribute userid: ObjectId( ), where ObjectID is referencing a document in the Users collection.How would you go about retrieving the user information (in this case, the user …

GC耗时高,原因竟是服务流量小?

简介 最近&#xff0c;我们系统配置了GC耗时的监控&#xff0c;但配置上之后&#xff0c;系统会偶尔出现GC耗时大于1s的报警&#xff0c;排查花了一些力气&#xff0c;故在这里分享下。 发现问题 我们系统分多个环境部署&#xff0c;出现GC长耗时的是俄罗斯环境&#xff0c;…

高校舆情监控系统建设(TOOM)如何做好教育行业舆情监控方案?

高校作为高密度学生聚集地&#xff0c;舆情管理上&#xff0c;需要保持高度的警惕性。高校中大学生是活跃在互联网上的重要群体&#xff0c;他们作为文化水平较高、思维较活跃的特殊群体&#xff0c;其网络中的言论合集往往会引发社会关注。高校舆情监控系统建设(TOOM)如何做好…

Sapped of vitality 生机已被耗尽 | 经济学人社论高质量双语精翻

选自TE20221217&#xff0c;leaders The global economy&#xff1a;Sapped of vitality 世界经济&#xff1a;生机已被耗尽 Why are the rich world’s politicians giving up on economic growth? 为什么发达国家的政客们不再追求经济增长目标&#xff1f; The prospect of …

智能音箱app开发-广州app开发定制

科技高速发展&#xff0c;智能产品遍地都是。日常生活都是智能化时代&#xff0c;智能音箱app也开始被开发出来。为用户提供便捷的服务&#xff0c;优化体验。 智能音箱app开发特点 一&#xff1a;搭建快速 线上渠道在各个行业中不可或缺的&#xff0c;因为线上平台不管是流量…

nginx学习笔记3(小d课堂)

nginx访问日志的作用&#xff1a; 我们先去查看一下我们的nginx.conf文件&#xff1a; BAT大厂应用运维平台案例统计 awk 默认以空格进行分隔。 {print $1} 只取第一个属性 sort -n排序 sort -rn倒序 uniq -c去重 head -n 100取前100个。 自定义日志统计接口性能 我们修改完…

上半年要写的博客文章28

上半年要写的博客文章21 这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个…

基于ESP32的蓝牙刷屏器自动点击器的制作

ESP32模块的选型&#xff1a; 这里是利用蓝牙连接手机来做点击器或刷屏器&#xff0c;ESP8266只有WIFI而ESP32有WIFI和蓝牙&#xff0c;所以选择ESP32模块。 ESP32模块可以选择ESP32-NodeMCU: 或ESP32-MiniKit: 这里使用的是ESP32 MINI KIT&#xff0c;Arduino环境下烧录选择如…

Nginx搭建Web服务器

环境&#xff1a; CentOS 7.2.1511 一、搭建静态web服务器 访问基本的静态页面&#xff08;基于IP访问&#xff09; 1.使用源码包编译安装nginx 启动ngin 直接在服务器测试访问&#xff1a; 访问nginx Web页面实现用户认证 修改nginx配置文件 2.生成密码文件&#xff…

64. 方法的值的传递及调用类内部的属性、方法

64. 方法的值的传递及调用类内部的属性、方法 文章目录64. 方法的值的传递及调用类内部的属性、方法1. 知识回顾2. 值的传递3. 没有值4. 需要向方法传递值5. 调用类内部的属性和方法6. 综合代码7. 类在爬虫中的应用7.1 创建类7.2 创建对象7.3 调用方法7.4 第2次调用方法7.5 第2…

MSE ZooKeeper 数据导入导出功能上线

作者&#xff1a;草谷 背景 MSE 提供了托管版的 ZooKeeper&#xff0c;拥有比自建开源 ZooKeeper 稳定性更高的SLA&#xff0c;同时管控面提供了丰富的服务自治功能。赶在2022年的岁末&#xff0c;MSE ZooKeeper 上线了一个非常实用的功能-数据导入导出功能&#xff0c;彻底解…

Mybatis自动生成增删改查代码

GitHub项目地址 Gitee项目地址 使用 mybatis generator 自动生成代码&#xff0c;实现数据库的增删改查。 1 配置Mybatis插件 在pom文件添加依赖&#xff1a; <plugins> <plugin><groupId>org.mybatis.generator</groupId><artifactId>myba…

宝塔面板Nginx开启Brotli压缩,提升网站加载速度

前言Google 认为互联网用户的时间是宝贵的&#xff0c;他们的时间不应该消耗在漫长的网页加载中&#xff0c;因此在 2015 年 9 月 Google 推出了无损压缩算法 Brotli。Brotli 通过变种的 LZ77 算法、Huffman 编码以及二阶文本建模等方式进行数据压缩&#xff0c;与 Gzip相比效率…

图解cross attention

英文参考链接&#xff1a; https://vaclavkosar.com/ml/cross-attention-in-transformer-architecture 交叉注意力与自我注意力 除了输入&#xff0c;cross-attention 计算与self-attention相同。交叉注意力不对称地组合了两个相同维度的独立嵌入序列&#xff0c;相比之下&a…

移动互联网社交江湖已定,抖音为何仍不放过微信?

进入2023年&#xff0c;抖音集团依然放不下“社交梦”。2022年12月30日&#xff0c;抖音官网上线了一款名为“抖音聊天”的桌面端聊天软件&#xff0c;提供Windows和Mac两个版本&#xff0c;进入软件需使用抖音App扫码登录。这并不是抖音集团首次推出社交产品。2019年以来&…