第三阶段应用层——2.10 视频监控—ALSA驱动层框架的简单分析
视频监控—ALSA驱动框架的简单分析
- 硬件平台:韦东山嵌入式Linxu开发板(S3C2440.v3)
- 软件平台:运行于VMware Workstation 12 Player下UbuntuLTS16.04_x64 系统
- 开发环境:arm-linux-gcc-4.3.2工具链、linux-3.4.2内核(开发版根文件系统)
- 源码仓库:https://gitee.com/d_1254436976/Embedded-Linux-Phase-3
目录
一、ALSA的简单介绍
ALSA是在Linux内核中的高级Linux声音体系结构,为Linux操作系统提供音频和MIDI功能。其具有以下重要功能:
- 对所有类型的音频接口的有效支持,从消费类声卡到专业的多通道音频接口。
- 完全模块化的声音驱动程序。
- SMP和线程安全设计。
- 用户空间库(alsa-lib)可以简化应用程序编程并提供更高级别的功能。
- 支持较早的Open Sound System(OSS)API,为大多数OSS程序提供二进制兼容性。
Linux中ALSA的主要文件:
include/sound/driver.h
sound/core/*.c
二、框架分析
此框架分析针对的是对声卡的控制接口与设备接口的结构,会忽略一些其他的东西。
1、sound.c文件分析
通过入口函数alsa_sound_init()
,来进行分析,得到如下图:
1.1 snd_open()
函数,关键snd_minor
数组
这个文件的file_operation
结构体对应的.open
函数,其要做一些初始化工作,找到对应的设备fops结构体:
- 得到某个设备的次设备号
- 根据次设备号在
snd_minor
数组中找到对应snd_minor
结构体 -
获取到对应的
fops
结构体
1.2 snd_minor
数组来源:snd_register_device_for_dev()
声卡设备注册函数
那么snd_minor
数组来自于哪里呢?
通过在sound.c
文件中搜索snd_minor
数组,找到在snd_register_device_for_dev()
函数构造:
- 根据传进来的参数设置
preg
,即snd_minor
结构体 - 把设置好的
preg
放入snd_minors
数组中 -
创建设备
1.3 谁来调用snd_register_device_for_dev()
,创建声卡设备结点
那么谁来调用snd_register_device_for_dev()
来创建声卡设备呢?
通过在内核中搜索,得到以下结果:
分为两个分支进行:
-
control.c文件的
snd_ctl_dev_register()
函数(snd_register_device_for_dev()
在core.h中定义的snd_register_device()
函数中被调用,snd_register_device()
最终在control.c文件的snd_ctl_dev_register()
函数调用) -
pcm.c文件的
snd_pcm_dev_register()
函数
1.4 小结
在sound.c文件中,主要做了一下事情:
-
调用
snd_register_device_for_dev()
,根据传入的参数构造了snd_minor
数组,并把传入的fops
结构体放入到数组中; - 在sound.c文件的
fops
结构体的.open
函数,获取到设备的fops
结构体
2、control.c文件分析
2.1 snd_ctl_dev_register()
的调用来源
通过在control.c文件中的追踪可以知道:
-
在
snd_ctl_create()
函数中,构建了snd_device_ops
结构体,在结构体内部把snd_ctl_dev_register()
联系起来; -
在
snd_ctl_dev_register()
函数中,把control.c文件中构建的file_operations
结构体传入到snd_register_device()
函数中,同时制定了这个控制接口的名字sprintf(name, "controlC%i", cardnum);
-
在
snd_register_device()
函数中,最终通过snd_register_device_for_dev()
函数把file_operations
结构体放入到snd_minor
数组 - 通过名字可以知道,control.c文件中构建的
file_operations
结构体,即snd_ctl_f_ops
,是与声卡控制接口相关的结构体。
2.2 谁来调用snd_ctl_create()
函数
通过内核的检索在发现:
- 在
init.c
文件中的snd_card_create()
中调用了snd_ctl_create()
2.3 小结
通过分析可以知道,这个分支的主要作用:
- 创建声卡的控制接口
-
调用
snd_register_device_for_dev()
,把与控制接口相关的fops结构体放入到snd_minior
数组中. - 声卡控制接口的名字为
controlC%i
3、pcm.c文件分析
3.1 snd_pcm_dev_register()
函数
在这个函数中,主要完成如下事:
- 根据传入的设备类型(录音/播放),注册对应的声卡设备
- 制定声卡设备的名字
-
根据上述信息,注册声卡设备节点
3.2 snd_pcm_dev_register()
的调用来源
通过在pcm.c文件中寻找可以知道如下调用顺序:
- 与上述control.c分析和相似的,在
_snd_pcm_new()
函数中构建了snd_device_ops
结构体,在结构体内部把snd_pcm_dev_register()
联系起来;
3.3 小结
通过分析可以知道,这个分支的主要作用:
- 创建声卡的设备接点,对于声卡的录音与播放,可以创建两个不同的设备节点;
-
最终调用
snd_register_device_for_dev()
,把与设备相关的fops结构体放入到snd_minior
数组中. -
声卡设备接口的名字为
pcmC%iD%ip
(播放)与"pcmC%iD%ic"
(录音)(其中, C0D0代表的是声卡0中的设备0, pcmC0D0c最后一个c代表capture, pcmC0D0p最后一个p代表
playback)
三、整体总结
通过上述的分析,得到了如下的框架图:
-
主要分为两个分支:注册声卡控制节点与声卡设备节点
-
在注册声卡控制节点分支中:
2.1 分配了内存,用来设置控制节点的结构体
2.2 制定了节点的名字
2.3 构造了控制接口相关的fops结构体
2.4 最终调用snd_register_device_for_dev()
,把与控制接口相关的fops结构体放入到snd_minior
数组中 -
在注册声卡设备节点分支中:
3.1 分配了内存,用来设置声卡设备节点的结构体
3.2 制定了声卡设备节点的名字
3.3 构造了声卡设备节点相关的fops结构体
3.4 最终调用snd_register_device_for_dev()
,把与声卡设备节点相关的fops结构体放入到snd_minior
数组中 -
在sound.c中,当用户打开声卡设备时
4.1 得到某个设备的次设备号
4.2 通过上述步骤得到的snd_minior
数组中,根据次设备好找到对应的snd_minor
结构体
4.3 进而在snd_minor
结构体中获得对应的fops结构体