一、ALSA基础知识
1. ALSA(Advanced Linux Sound Architecture)目前已经成为了linux的主流音频体系结构,ALSA开源项目网址:http://www.alsa-project.org/。
另一个音频驱动框架是OSS(open sound system),收费,已经废弃。
2.在内核设备驱动层,ALSA提供了alsa-driver,同时在应用层,ALSA提供了alsa-lib,应用程序只要调用alsa-lib提供的API,即可以完成对底层音频硬件的控制。
3.PCM(Pulse-code modulation)是脉冲编码调制,PCM信号的两个重要指标是采样频率和量化精度,目前,CD音频的采样频率通常为44100Hz,量化精度是16bit。
播放音乐时,应用程序从存储介质中读取音频数据(MP3、WMA、AAC...),经过解码后,最终送到音频驱动程序中的就是PCM数据;在录音时,音频驱动不停地把采样所得的PCM数据送回给应用程序,由应用程序完成压缩、存储等任务。所以,音频驱动的两大核心任务就是:
playback:如何把用户空间的应用程序发过来的PCM数据,转化为人耳可以辨别的模拟音频
capture:把mic拾取到得模拟信号,经过采样、量化,转换为PCM信号送回给用户空间的应用程序
4.采集两路数据称为双通道,wav格式的文件就是原始的采集声音数据的文件,压缩后可为mp3文件。
5.音频驱动入口文件(注册主设备号的文件)
alsa_sound_init //sound\core\sound.c
register_chrdev(116, "alsa", &snd_fops) //snd_fops中只有open()
音频系统创建的所有设备文件都以struct snd_minor的形式存储在全局数据snd_minors[]中,snd_fops.open()根据次设备号起中转功能。
6.ALSA发展历程:ALSA ---> ASoC --->DAPM,ASoC和DAPM将在后续博客讲。
7.相关概念
HiFi:High-Fidelity的缩写,翻译为“高保真”,其定义是:与原来的声音高度相似的重放声音。
PCM: Pulse-code modulation,中文译名是脉冲编码调制。
DAI: Digital Audio Interface
MIDI:Music Instrument Digital Interface
二、Control设备的创建
1. Control接口主要让用户空间的应用程序(alsa-lib)可以访问和控制音频codec芯片中的多路开关,滑动控件等。对于Mixer(混音)来说,Control接口显得尤为重要,从ALSA 0.9.x版本开始,所有的mixer工作都是通过control接口的API来实现的。使用snd_kcontrol_new结构来定义一个Control项,根据codec的芯片手册进行构造snd_kcontrol_new。
2.设置cidec配置的统一的接口就是snd_kcontrol,一个snd_kcontrol表示一个功能(可能是一个寄存器的某些位),每个sndkcontrol中有自己的读写函数。一个声卡有多个kcontrol,一个kcontrol对应一个功能,比如:音量,开关录音。kcontrol中有函数来设置功能。snd_kcontrol对应的是功能,其寄存器配置由codec驱动负责。
3.kcontrol创建过程示例
struct snd_kcontrol_new wm8960_snd_controls[] //wm8960.c
snd_soc_add_controls(codec, wm8960_snd_controls, ARRAY_SIZE(wm8960_snd_controls));
snd_ctl_add(card, snd_soc_cnew(control, codec, control->name, codec->name_prefix));//将snd_kcontrol_new结构转换成snd_kcontrol结构
snd_soc_cnew(control, codec, control->name, codec->name_prefix)//获取一个snd_kcontrol结构
kcontrol = snd_ctl_new1(&template, data);//然后将这些snd_kcontrol结构串接在snd_card.controls域中。
list_add_tail(&kcontrol->list, &card->controls);
二、声卡的创建
1. 使用struct snd_card表示,其是一个父设备,下面挂载着control pcm节点分别使用snd_device结构表示。snd_card可以说是整个ALSA音频驱动最顶层的一个结构,整个声卡的软件逻辑结构开始于该结构,几乎所有与声音相关的逻辑设备都是在snd_card的管理之下,声卡驱动的第一个动作通常就是创建一个snd_card结构体。
2. 声卡的创建过程
snd_card_create //sound/core/init.c//创建声卡的控制接口
snd_ctl_create(card); //sound/core/control.c//在声卡注册的时候会调用所有组件的dev_register回调来创建对应的设备节点:
snd_card_register(struct snd_card *card);//sound/core/init.c
snd_device_register_all(card)
list_for_each_entry(dev,&card->devices, list)
dev->ops->dev_register(dev) //注册所有的属于此Card的设备节点//对应control节点
snd_device_ops.dev_register =snd_ctl_dev_register,
snd_register_device(SNDRV_DEVICE_TYPE_CONTROL,&snd_ctl_f_ops, /*name=*/"controlC0")//对应pcm节点
.dev_register =snd_pcm_dev_register,
snd_register_device_for_dev(&snd_pcm_f_ops[0:p/1:c]);
声卡设备/dev/snd/controlCX的file_operations是snd_ctl_f_ops//sound/core/control.c
声卡设备/dev/snd/pcmCXDXp的file_operations是snd_pcm_f_ops[0], /dev/snd/pcmCXDXc的file_operations是snd_pcm_f_ops[1] //pcm_native.c
4. 一个pcm就是一个逻辑device,它里面有两个通道,一个是playback通道,对应/dev/pcmC0D0p节点,另一个是capture通道,对应/dev/pcmC0D0c节点.
5. 创建声卡的功能部件(逻辑设备),例如PCM,Mixer,MIDI等的函数如下
PCM —— snd_pcm_new()
snd_device_new(card, SNDRV_DEV_PCM, pcm,&ops)
RAWMIDI —— snd_rawmidi_new()
snd_device_new(card, SNDRV_DEV_RAWMIDI, rmidi,&ops)
CONTROL —— snd_ctl_create()
snd_device_new(card, SNDRV_DEV_CONTROL, card,&ops);
TIMER —— snd_timer_new()
snd_device_new(card, SNDRV_DEV_TIMER, timer,&ops);
INFO —— snd_card_proc_new()
snd_device_new(card, SNDRV_DEV_INFO, entry,&ops)
JACK —— snd_jack_new()
snd_device_new(card, SNDRV_DEV_JACK, jack,&ops);
参考:
Linux ALSA声卡驱动之一:ALSA架构简介:https://blog.csdn.net/DroidPhone/article/details/6271122
Linux ALSA声卡驱动之二:声卡的创建:https://blog.csdn.net/droidphone/article/details/6289712
Linux ALSA声卡驱动之三:PCM设备的创建:https://blog.csdn.net/droidphone/article/details/6308006
Linux ALSA声卡驱动之四:Control设备的创建 :https://blog.csdn.net/gjy938815/article/details/9209457