程序项目代做,有需求私信(vue、React、Java、爬虫、电路板设计、嵌入式linux等)

Rockchip RK3399 - ALSA Proc Info

----------------------------------------------------------------------------------------------------------------------------

开发板 :NanoPC-T4开发板
eMMC :16GB
LPDDR3 :4GB
显示屏 :15.6英寸HDMI接口显示屏
u-boot :2023.04
linux   :6.3
----------------------------------------------------------------------------------------------------------------------------

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

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

一、/proc/asound

ALSA有自己的proc tree,在/proc/asound这个目录下可以找到许多关于snd card 的详细信息,Proc Files of ALSA Drivers

root@rk3399:/# ll /proc/asound
dr-xr-xr-x   5 root root 0 Aug  6 16:43 card0/
dr-xr-xr-x   5 root root 0 Aug  6 16:55 card1/
-r--r--r--   1 root root 0 Aug  6 15:10 cards
-r--r--r--   1 root root 0 Aug  6 16:55 devices
lrwxrwxrwx   1 root root 5 Aug  6 16:55 hdmisound -> card0/
-r--r--r--   1 root root 0 Aug  6 16:55 pcm
lrwxrwxrwx   1 root root 5 Aug  6 16:55 realtekrt5651co -> card1/
dr-xr-xr-x   6 root root 0 Aug  6 16:55 seq/
-r--r--r--   1 root root 0 Aug  6 16:55 timers
-r--r--r--   1 root root 0 Aug  6 16:55 version

其中主要的节点如下:

  • 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>;

该节主要用于讲解在alsa core 中创建的/proc/asound目录树以及如何实现的。

在 alsa_sound_init函数中会调用snd_info_init函数创建 /proc/asound目录,并将该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;
}

1.1 version文件

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

root@rk3399:/#  cat /proc/asound/version
Advanced Linux Sound Architecture Driver Version k6.3.0.

1.2 devices文件

接着在snd_proc_root entry下创建 “devices” 文件(即 /proc/asound/devices),提供了read方法,cat /proc/asound/devices如下:

root@rk3399:/# cat /proc/asound/devices
  1:        : sequencer
  2: [ 0- 0]: digital audio playback
  3: [ 0- 0]: digital audio capture
  4: [ 0]   : control
  5: [ 1- 0]: digital audio playback
  6: [ 1- 0]: digital audio capture
  7: [ 1]   : control
 33:        : timer

对于devices的print格式如下:

  • Control设备: “minor: [card_id] : control”;
  • PCM设备:“minor: [card_id- device_id]: digital audio playback/capture”;
  • timer设备: “minor: : timer”;

1.3 cards文件

接着在snd_proc_root entry下创建 “cards” 文件(即 /proc/asound/cards),提供了read方法,cat /proc/asound/cards如下:

root@rk3399:/# cat /proc/asound/cards
 0 [hdmisound      ]: simple-card - hdmi-sound
                      hdmi-sound
 1 [realtekrt5651co]: simple-card - realtek,rt5651-codec
                      realtek,rt5651-codec

对于cards的print格式如下:

card_id [card_id_string    ]:    card_driver - card_shortname
                            card_longname

1.4 cardx目录

我们前面已经分析了创建声卡函数snd_card_new的执行流程,其内部会调用snd_info_card_create在snd_proc_root下创建 "cardx" 目录(即/proc/asound/cardx),并将对应的entry保存在card->proc_root,以便后面基于该声卡的snd device等节点均以其作为 parent entry;

root@rk3399:/# ll /proc/asound/card0
-r--r--r--  1 root root 0 Aug  6 16:43 id
dr-xr-xr-x  5 root root 0 Aug  6 16:43 pcm0c/
dr-xr-xr-x  5 root root 0 Aug  6 16:43 pcm0p/

在cardx目录下主要会对每个PCM设备创建对应的pcmxp/c目录,创建方式如下:

  • 我们都知道在创建PCM设备时都调用snd_pcm_new函数,在该函数中也分别会对Playback&Capture调用snd_pcm_new_stream(PLAYBACK/CAPTURE)定义playback&capture设备名称;
  • 然后则会调用snd_pcm_stream_proc_init函数,在该函数中会在card->proc_root entry下创建pcmxp/c目录(即 /proc/asound/cardx/pcmxp | pcmxc),并将对应的 entry 保存在 pcm->streams[PLAYBACK/CAPTURE]->proc_root;同时也会在 pcm->streams[]->proc_root下创建info文件(即/proc/asound/cardx/pcmxp|c/info),并提供read方法;

经过上述创建目录以及cat /proc/asound/cardx/pcmxp|c/info 如下所示:

root@rk3399:/# cat /proc/asound/card0/pcm0p/info
card: 0
device: 0
subdevice: 0
stream: PLAYBACK
id: ff8a0000.i2s-i2s-hifi i2s-hifi-0
name: ff8a0000.i2s-i2s-hifi i2s-hifi-0
subname: subdevice #0
class: 0
subclass: 0
subdevices_count: 1
subdevices_avail: 1
root@rk3399:/# cat /proc/asound/card1/pcm0p/info
card: 1
device: 0
subdevice: 0
stream: PLAYBACK
id: ff880000.i2s-rt5651-aif1 rt5651-aif1-0
name: ff880000.i2s-rt5651-aif1 rt5651-aif1-0
subname: subdevice #0
class: 0
subclass: 0
subdevices_count: 1
subdevices_avail: 1

对于pcm播放的最小单元是substream,故接着在snd_pcm_new_stream会对该pcm playback/capture stream下所有的substreams(substream_count一般都是1)调用snd_pcm_substream_proc_init函数,即在pcm->streams[]->proc root下创建subx目录(即/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后如下(在音频播放状态下执行):

root@rk3399:/# cd /proc/asound/card0/pcm0p/sub0
root@rk3399:/proc/asound/card0/pcm0p/sub0# ll
-r--r--r-- 1 root root 0 Aug  6 17:04 hw_params
-r--r--r-- 1 root root 0 Aug  6 17:04 info
-rw-r--r-- 1 root root 0 Aug  6 17:04 prealloc
-r--r--r-- 1 root root 0 Aug  6 17:04 prealloc_max
-r--r--r-- 1 root root 0 Aug  6 17:04 status
-r--r--r-- 1 root root 0 Aug  6 17:04 sw_params
--w------- 1 root root 0 Aug  6 17:04 xrun_injection
root@rk3399:/proc/asound/card0/pcm0p/sub0# cat info
card: 0
device: 0
subdevice: 0
stream: PLAYBACK
id: ff8a0000.i2s-i2s-hifi i2s-hifi-0
name: ff8a0000.i2s-i2s-hifi i2s-hifi-0
subname: subdevice #0
class: 0
subclass: 0
subdevices_count: 1
subdevices_avail: 0
root@rk3399:/proc/asound/card0/pcm0p/sub0# cat hw_params
access: RW_INTERLEAVED
format: S16_LE
subformat: STD
channels: 2
rate: 44100 (44100/1)
period_size: 5513
buffer_size: 22052
root@rk3399:/proc/asound/card0/pcm0p/sub0# cat sw_params
tstamp_mode: NONE
period_step: 1
avail_min: 5513
start_threshold: 22052
stop_threshold: 22052
silence_threshold: 0
silence_size: 0
boundary: 6207086186423386112
root@rk3399:/proc/asound/card0/pcm0p/sub0# cat status
state: RUNNING
owner_pid   : 5313
trigger_time: 7044.021765728
tstamp      : 0.000000000
delay       : 20524
avail       : 1528
avail_max   : 16539
-----
hw_ptr      : 2697409
appl_ptr    : 2717933

如上所示,对于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&write方法,对该节点执行cat&echo如下:

root@rk3399:/proc/asound/card0/pcm0p/sub0# cat prealloc
512
root@rk3399:/proc/asound/card0/pcm0p/sub0# cat prealloc_max
18014398509481983
root@rk3399:/proc/asound/card0/pcm0p/sub0# echo 512 > prealloc
root@rk3399:/proc/asound/card0/pcm0p/sub0# cat prealloc
512

1.5 pcm

在sound/core/pcm.c下alsa_pcm_info中会调用snd_pcm_proc_init函数,即会在snd_proc_root下创建pcm文件(即 /proc/asound/pcm),并提供read方法,cat /proc/asound/pcm 后如下:

root@rk3399:/proc/asound/card0/pcm0p/sub0#  cat /proc/asound/pcm
00-00: ff8a0000.i2s-i2s-hifi i2s-hifi-0 : ff8a0000.i2s-i2s-hifi i2s-hifi-0 : playback 1 : capture 1
01-00: ff880000.i2s-rt5651-aif1 rt5651-aif1-0 : ff880000.i2s-rt5651-aif1 rt5651-aif1-0 : playback 1 : capture 1

参考文章

[1] RK3399 探索之旅 / Audio 驱动层速读

[2] Linux ALSA音频驱动之一:框架概述

[3] Linux音频子系统

[4] Linux ALSA 音频系统:物理链路篇

[5] Linux ALSA 之五:ALSA Proc Info

posted @ 2023-07-09 23:33  大奥特曼打小怪兽  阅读(151)  评论(0编辑  收藏  举报
如果有任何技术小问题,欢迎大家交流沟通,共同进步