Linux ALSA 之五:ALSA Proc Info

news2024/11/26 22:46:10

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/153680.html

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

相关文章

企业不可忽视的舆情监测管理办法,TOOM舆情监控工作总结?

企业做好舆情监控以及舆情管理是对企业负责&#xff0c;在企业发展过程中不可能是一帆风顺的&#xff0c;少不了各种各样的流言蜚语&#xff0c;像舆情监控管理监测早知早解决。接下来我们简单了解企业不可忽视的舆情监测管理办法&#xff0c;TOOM舆情监控工作总结? 一、企业…

【NI Multisim 14.0原理图设计基础——调整元器件位置】

目录 序言 一、调整元器件位置 &#x1f34a;1.元器件的移动 &#x1f34a;2.元器件的旋转 &#x1f34a;3.元器件的对齐 序言 NI Multisim最突出的特点之一就是用户界面友好。它可以使电路设计者方便、快捷地使用虚拟元器件和仪器、仪表进行电路设计和仿真。 首先启动NI…

【自学Python】Python print()函数

Python print()函数 Python print()函数教程 在 Python 中&#xff0c;print() 函数用于打印相应的信息到终端控制台&#xff0c;同时 print() 函数可以支持同时输出一个或多个 变量。 Python print()函数详解 语法 print(*objects, sep , end\n, filesys.stdout, flushFa…

线性代数 --- 投影Projection 六(向量在子空间上的投影)

向量b在多维子空间上的投影回顾&#xff1a;向量在向量上&#xff08;直线上&#xff09;的投影在研究向量在子空间上的投影前&#xff0c;先回顾一下前面学习的一个任意向量b在另一个向量a上的投影&#xff0c;共三个部分。1&#xff0c;求权重系数&#xff08;A constant&…

2022 general purpose in-context learning by meta-learning transformers

wps: option left 回到上一个视图 Kirsch L, Harrison J, Sohl-Dickstein J, et al. General-purpose in-context learning by meta-learning transformers[J]. arXiv preprint arXiv:2212.04458, 2022. 目录Kirsch L, Harrison J, Sohl-Dickstein J, et al. General-purpose…

【高校节能】高校电力能源智能管理系统设计目标与原则

摘 要&#xff1a;高校构建电力能源智能管理系统&#xff0c;可以实现对高校电力能源消耗的实时监测、分析预警和辅助决策。系统通过能效管理技术监测各个设备的用电情况&#xff0c;并通过数据的取得、整合、汇总来实现能源的绩效管理。系统从全局出发&#xff0c;整体调控电…

CCF BDCI | 算能赛题决赛选手说明论文-03

基于TPU平台实现人群密度估计∗ ChaMd5-AI 唐晶机械工程&博士二年级 华中科技大学 中国-武汉 j_tanghust.edu.cn 团队简介 唐晶&#xff0c;2001年生&#xff0c;本科毕业于华中科技大学机械卓越工程师班&#xff0c;现为华中科技大学机械科学与工程学院陶波教授课题组博…

视频实时自然美颜, 无惧素颜上镜

华为HMS Core 视频编辑服务依托自身AI技术的核心优势&#xff0c;在最新版本HMS Core 6.8.0中上线了全新的视频美颜功能&#xff0c;能对指定图片或视频中的人脸实现磨皮、美白、大眼、瘦脸的美颜效果&#xff0c;适用于直播、相机、视频剪辑、图片处理等场景中&#xff0c;打造…

cubeIDE开发, stm32的GPIO原理、cubeMX配置及底层源码实现分析

一、GPIO介绍 1.1 GPIO 简述 GPIO(General purpose input/output&#xff0c;通用型输入输出)&#xff0c;一个引脚可以用于输入、输出或其他特殊功能&#xff0c;PIN脚依现实需要可作为通用输入&#xff08;GPI&#xff09;或通用输出&#xff08;GPO&#xff09;或通用输入与…

鑫磊股份开启申购:资产负债率较高,实控人控制企业借款高企

1月10日&#xff0c;鑫磊压缩机股份有限公司&#xff08;下称“鑫磊股份”&#xff0c;SZ:301317&#xff09;开启申购&#xff0c;发行价格20.67元/股&#xff0c;市盈率58.65倍。据贝多财经了解&#xff0c;鑫磊股份将在深圳证券交易所创业板上市。 本次上市&#xff0c;鑫磊…

LinuxC—进程

进程 1 进程标识符pid 基本概念 类型pid_t&#xff0c;是一个有符号16位整数&#xff0c;进程号是顺次向下使用(fd是优先使用当前可用最小的) shell中的ps命令能够查看当前系统的进程信息快照 相关函数 getpid(2)获取当前进程的进程号 /* Get the process ID of the calling…

中断处理程序

文章目录前言前置知识中断概念中断分类实验操作实验一实验二实验三前言 博客记录《操作系统真象还原》第七章实验的操作~ 实验环境&#xff1a;ubuntu18.04VMware &#xff0c; Bochs下载安装 实验内容&#xff1a; 编写中断处理程序&#xff08; 操作 8259A 打开中断&…

2023年浙江食品安全管理员考试真题题库及答案

百分百题库提供食品安全管理员考试试题、食品安全管理员考试预测题、食品安全管理员考试真题、食品安全管理员证考试题库等&#xff0c;提供在线做题刷题&#xff0c;在线模拟考试&#xff0c;助你考试轻松过关。 一、多选题 1.餐具清洗消毒水池与以下哪些水池应分开&#xff…

机器学习— —导入数据

DAY1集成开发环境原始数据展示主要函数介绍data.iloc()函数dataset.iloc[0]dataset.iloc[:,:-1]dataset.iloc[:,3]dataset.iloc[1:3,1]可执行代码导入结果展示我的写在最后集成开发环境 Spyder (前身是 Pydee) 是一个强大的交互式 Python 语言开发环境&#xff0c;提供高级的代…

如何搭建Python环境和安装Pycharm

1、 搭建Python的基础环境 Anaconda简介 Anaconda指的是一个开源的Python发行版本&#xff0c;其包含了conda、Python等180多个科学包及其依赖项。 因为包含了大量的科学包&#xff0c;Anaconda 的下载文件比较大&#xff08;约 531 MB&#xff09;&#xff0c;如果只需要某些…

【Kotlin】标准库函数 ② ( run 标准库函数 | run 函数传入 Lambda 表达式作为参数 | run 函数传入函数引用作为参数 )

文章目录一、run 标准库函数1、run 函数传入 Lambda 表达式作为参数2、run 函数传入函数引用作为参数Kotlin 语言中 , 在 Standard.kt 源码中 , 为所有类型定义了一批标准库函数 , 所有的 Kotlin 类型都可以调用这些函数 ; 一、run 标准库函数 1、run 函数传入 Lambda 表达式作…

Odoo丨5步轻松实现在Odoo中打开企微会话框

文章目录一、前言二、实现方案三、接口调用步骤一、前言 企业微信作为一个很好的企业级应用发布平台&#xff0c;尤其是提供的数据和接口&#xff0c;极大地为很多企业级应用提供便利&#xff0c;在日常中应用广泛&#xff01; 最近在项目中就遇到一个与企业微信相关的场景开…

商标异议解读

商标异议解读《商标法》第三十五条规定&#xff0c;对初步审定公告的商标提出异议的&#xff0c;商标局应当听取异议人和被异议人陈述事实和理由&#xff0c;经调查核实后&#xff0c;自公告期满之日起十二个月内做出是否准予注册的决定&#xff0c;并书面通知异议人和被异议人…

Python初次实现MapReduce——WordCount

前言 Hadoop 本身是用 Java 开发的&#xff0c;所以之前的MapReduce代码小练都是由Java代码编写&#xff0c;但是通过Hadoop Streaming&#xff0c;我们可以使用任意语言来编写程序&#xff0c;让Hadoop 运行。 本文用Python语言实现了词频统计功能&#xff0c;最后通过Hadoo…

Redis从青铜到王者,从环境搭建到熟练使用

一、常见的非关系型数据库NOSQL分类NOSQL类型主要数据库产品类型特色K-V键值对存储类型Redis、Memcached使用key可以快速的查询到value&#xff0c;Memcached可以支持String类型的值value&#xff0c;Redis支持的值的数据类型很多如&#xff1a;String\set\hash\sortset\list等…