linux下音频设备驱动

Posted DS小龙哥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux下音频设备驱动相关的知识,希望对你有一定的参考价值。

Linux下音频设备驱动​

音频设备框架

Linux下音频设备的核心文件:\\sound\\sound_core.c

1.1.1 数字音频简介

音频信号是一种连续变化的模拟信号,但计算机只能处理和记录二进制的数字信号,由自然音源得到的音频信号必须经过一定的变换,成为数字音频信号之后,才能送到计算机中作进一步的处理。

数字音频系统通过将声波的波型转换成一系列二进制数据,来实现对原始声音的重现,实现这一步骤的设备常被称为模/数转换器(A/D)。A/D转换器以每秒钟上万次的速率对声波进行采样,每个采样点都记录下了原始模拟声波在某一时刻的状态,通常称之为样本(sample),而每一秒钟所采样的数目则称为采样频率,通过将一串连续的样本连接起来,就可以在计算机中描述一段声音了。对于采样过程中的每一个样本来说,数字音频系统会分配一定存储位来记录声波的振幅,一般称之为采样分辨率或者采样精度,采样精度越高,声音还原时就会越细腻。

数字音频涉及到的概念非常多,对于在Linux下进行音频编程的程序员来说,最重要的是理解声音数字化的两个关键步骤:采样和量化。采样就是每隔一定时间就读一次声音信号的幅度,而量化则是将采样得到的声音信号幅度转换为数字值,从本质上讲,采样是时间上的数字化,而量化则是幅度上的数字化。

下面介绍几个在进行音频编程时经常需要用到的技术指标:

  • 采样频率采样频率是指将模拟声音波形进行数字化时,每秒钟抽取声波幅度样本的次数。采样频率的选择应该遵循奈奎斯特(Harry Nyquist)采样理论:如果对某一模拟信号进行采样,则采样后可还原的最高信号频率只有采样频率的一半,或者说只要采样频率高于输入信号最高频率的两倍,就能从采样信号系列重构原始信号。正常人听觉的频率范围大约在20Hz~20kHz之间,根据奈奎斯特采样理论,为了保证声音不失真,采样频率应该在40kHz左右。常用的音频采样频率有8kHz、11.025kHz、22.05kHz、16kHz、37.8kHz、44.1kHz、48kHz等,如果采用更高的采样频率,还可以达到DVD的音质。
  • 量化位数量化位数是对模拟音频信号的幅度进行数字化,它决定了模拟信号数字化以后的动态范围,常用的有8位、12位和16位。量化位越高,信号的动态范围越大,数字化后的音频信号就越可能接近原始信号,但所需要的存贮空间也越大。
  • 声道数声道数是反映音频数字化质量的另一个重要因素,它有单声道和双声道之分。双声道又称为立体声,在硬件中有两条线路,音质和音色都要优于单声道,但数字化后占据的存储空间的大小要比单声道多一倍。

1.1.2 声卡驱动

出于对安全性方面的考虑,Linux下的应用程序无法直接对声卡这类硬件设备进行操作,而是必须通过内核提供的驱动程序才能完成。在Linux上进行音频编程的本质就是要借助于驱动程序,来完成对声卡的各种操作。对硬件的控制涉及到寄存器中各个比特位的操作,通常这是与设备直接相关并且对时序的要求非常严格,如果这些工作都交由应用程序员来负责,那么对声卡的编程将变得异常复杂而困难起来,驱动程序的作用正是要屏蔽硬件的这些底层细节,从而简化应用程序的编写。

目前Linux下常用的声卡驱动程序主要有两种:OSS和ALSA。

ALSA和OSS最大的不同之处在于ALSA是由志愿者维护的自由项目,而OSS则是由公司提供的商业产品,因此在对硬件的适应程度上OSS要优于ALSA,它能够支持的声卡种类更多。ALSA虽然不及OSS运用得广泛,但却具有更加友好的编程接口,并且完全兼容于OSS,对应用程序员来讲无疑是一个更佳的选择。

OSS和ALSA,前者包含dsp和mixer字符设备接口,在用户空间的编程中,完全使用文件操作;后者以card和组件(pcm、mixer等)为主线,在用户空间的编程中不使用文件接口而使用alsalib。

1.1.3 Linux OSS音频设备驱动的组成

OSS标准中有2个最基本的音频设备:mixer(混音器)和DSP(数字信号处理器)。

在声卡的硬件电路中,mixer是一个很重要的组成部分,它的作用是将多个信号组合或者叠加在一起,对于不同的声卡来说,其混音器的作用可能各不相同。OSS驱动中,/dev/mixer设备文件是应用程序对mixer进行操作的软件接口。(Mixer混音设备用于将来源不同位置的声音合成一个数据再传递给音频解码设备进行播放)

混音器电路通常由两个部分组成:输入混音器(input mixer)和输出混音器(output mixer)。输入混音器负责从多个不同的信号源接收模拟信号,这些信号源有时也被称为混音通道或者混音设备。模拟信号通过增益控制器和由软件控制的音量调节器后,在不同的混音通道中进行级别(level)调制,然后被送到输入混音器中进行声音的合成。混音器上的电子开关可以控制哪些通道中有信号与混音器相连,有些声卡只允许连接一个混音通道作为录音的音源,而有些声卡则允许对混音通道做任意的连接。经过输入混音器处理后的信号仍然为模拟信号,它们将被送到A/D转换器进行数字化处理。

输出混音器的工作原理与输入混音器类似,同样也有多个信号源与混音器相连,并且事先都经过了增益调节。当输出混音器对所有的模拟信号进行了混合之后,通常还会有一个总控增益调节器来控制输出声音的大小,此外还有一些音调控制器来调节输出声音的音调。经过输出混音器处理后的信号也是模拟信号,它们最终会被送给喇叭或者其它的模拟输出设备。对混音器的编程包括如何设置增益控制器的级别,以及怎样在不同的音源间进行切换,这些操作通常来讲是不连续的,而且不会像录音或者放音那样需要占用大量的计算机资源。由于混音器的操作不符合典型的读/写操作模式,因此除了 open()和close()两个系统调用之外,大部分的操作都是通过ioctl()系统调用来完成的。与/dev/dsp不同,/dev/mixer允许多个应用程序同时访问,并且混音器的设置值会一直保持到对应的设备文件被关闭为止。

DSP也称为编解码器,实现录音(录音)和放音(播放),其对应的设备文件是/dev/dsp或/dev/sound/dsp。OSS声卡驱动程序提供的 /dev/dsp是用于数字采样和数字录音的设备文件,向该设备写数据即意味着激活声卡上的D/A转换器进行放音,而向该设备读数据则意味着激活声卡上的 A/D转换器进行录音。

在从DSP设备读取数据时,从声卡输入的模拟信号经过A/D转换器变成数字采样后的样本,保存在声卡驱动程序的内核缓冲区中,当应用程序通过 read()系统调用从声卡读取数据时,保存在内核缓冲区中的数字采样结果将被复制到应用程序所指定的用户缓冲区中。需要指出的是,声卡采样频率是由内核中的驱动程序所决定的,而不取决于应用程序从声卡读取数据的速度。如果应用程序读取数据的速度过慢,以致低于声卡的采样频率,那么多余的数据将会被丢弃(即overflow);如果读取数据的速度过快,以致高于声卡的采样频率,那么声卡驱动程序将会阻塞那些请求数据的应用程序,直到新的数据到来为止。

在向DSP设备写入数据时,数字信号会经过D/A转换器变成模拟信号,然后产生出声音。应用程序写入数据的速度应该至少等于声卡的采样频率,过慢会产生声音暂停或者停顿的现象(即underflow)。如果用户写入过快的话,它会被内核中的声卡驱动程序阻塞,直到硬件有能力处理新的数据为止。

与其它设备有所不同,声卡通常不需要支持非阻塞(non-blocking)的I/O操作。即便内核OSS驱动提供了非阻塞的I/O支持,用户空间也不宜采用。

无论是从声卡读取数据,或是向声卡写入数据,事实上都具有特定的格式(format),如无符号8位、单声道、8KHz采样率,如果默认值无法达到要求,可以通过ioctl()系统调用来改变它们。通常说来,在应用程序中打开设备文件/dev/dsp之后,接下去就应该为其设置恰当的格式,然后才能从声卡读取或者写入数据。

1.1.4 音频框架结构图

1、linux下的声卡驱动架构主要分为OSS架构和ALSA架构。

2、OSS架构

OSS全称是Open Sound System,叫做开放式音频系统,这种早期的音频系统这种基于文件系统的访问方式,这意味着对声音的操作完全可以像对普通文件那样执行open,read等操作。OSS中,主要提供了以下几种音频设备的抽象设备文件:

/dev/mixer:用来访问声卡中的混音器用于调整音量大小和选择音源

/dev/dsp、/dev/audio:读这个设备就相当于录音,写这个设备就相当于放音。

2、ALSA架构:

由于OSS设计上的缺陷,导致其对混音的支持不好,再加上2002年以后,OSS成为商业不开源软件,这就催生了Linux下另一种音频系统ALSA的出现,ALSA全称是AdvancedLinux Sound Architecture,叫做Linux系统高级音频架构,它主要为声卡提供的驱动组件,以替代原先的OSS。

  • ALSA架构借助于如下设备文件工作:/dev/pcmC0D0c:用于录音的pcm设备
    /dev/pcmC0D0p:用于播放的pcm设备
    /dev/timer:定时器
    /dev/controlC0:用于声卡的控制,如通道选择
    /dev/mixer:混音处理
  • linux下音频设备驱动_linux

音频设备函数接口

1.2.1注册一个混器设备

int register_sound_mixer(const struct file_operations *fops, int dev)

功能:注册一个混音器设备

第1个参数fops即是文件操作接口。(就是字符设备标准文件操作接口)

第2个参数dev是设备编号,如果填入-1,则系统自动分配1个设备编号,返回值就是分配的设备编号。

mixer 是 1个典型的字符设备,因此编码的主要工作是实现file_operations中的open()、ioctl()等函数。

mixer接口file_operations中的最重要函数是ioctl(),它实现混音器的不同IO控制命令。

注:可以查看内核自带的例子程序来看该函数的用法!

安装好之后生成的节点名称:

[root@XL /mnt/test]# ls /dev/mixer -l

crw-rw---- 1 root root 14, 0 Jan 1 17:15 /dev/mixer

1.2.2 注销一个混音器设备

void unregister_sound_mixer(int unit)

功能:注销一个混音器设备

参数:次设备号,与register_sound_mixer函数匹配。

1.2.3 注册DSP编解码器设备

int register_sound_dsp(const struct file_operations *fops, int dev)

参数:

第一个参数:字符设备文件操作集合

第二个参数:次设备号,如果填-1表示自动分配次设备号,返回值就是次设备号。

dsp也是1个典型的字符设备,因此编码的主要工作是实现file_operations中的read()、write()、ioctl()等函数。

dsp接口file_operations中的read()和write()函数非常重要,read()函数从音频控制器中获取录音数据到缓冲区并拷贝到用户空间,write()函数从用户空间拷贝音频数据到内核空间缓冲区并最终发送到音频控制器。

dsp接口file_operations中的ioctl()函数处理对采样率、量化精度、DMA缓冲区块大小等参数设置IO控制命令的处理。

数据从缓冲区拷贝到音频控制器的过程中,通常会使用DMA,DMA对声卡而言非常重要。例如,在放音时,驱动设置完DMA控制器的源数据地址(内存中 DMA缓冲区)、目的地址(音频控制器FIFO)和DMA的数据长度,DMA控制器会自动发送缓冲区的数据填充FIFO,直到发送完相应的数据长度后才中断一次。

在OSS驱动中,建立存放音频数据的环形缓冲区(ring buffer)通常是值得推荐的方法。此外,在OSS驱动中,一般会将1个较大的DMA缓冲区分成若干个大小相同的块(这些块也被称为“段”,即 fragment),驱动程序使用DMA每次在声音缓冲区和声卡之间搬移一个fragment。在用户空间,可以使用ioctl()系统调用来调整块的大小和个数。

除了read()、write()和ioctl()外,dsp接口的poll()函数通常也需要被实现,以向用户反馈目前能否读写DMA缓冲区。

在OSS驱动初始化过程中,会调用register_sound_dsp()和register_sound_mixer()注册dsp和mixer设备;在模块卸载的时候,会调用unregister_sound_dsp(audio_dev_dsp)和unregister_sound_mixer(audio_dev_mixer)。

  • 注册成功后生成的设备节点:

[root@XL /mnt/test]# ls /dev/dsp -l

crw-rw---- 1 root root 14, 3 Jan 1 17:15 /dev/dsp


1.2.4 注销DSP编解码器设备

void unregister_sound_dsp(int unit)

参数:注册的时候填充的次设备号。


1.2.5 注册框架示例

#include <linux/kernel.h>

#include <linux/module.h>

#include <linux/miscdevice.h>

#include <linux/fs.h>

#include <sound/core.h>

#include <linux/soundcard.h>

#include <linux/sound.h>

#include <linux/slab.h>

#include <linux/soundcard.h>



//会被应用层的open函数调用

static int tiny4412_open(struct inode *my_inode, struct file *my_file)

printk("open函数调用成功!\\n");

return 0;



// 应用程序结束的时候自动调用

static int tiny4412_release(struct inode *my_inode, struct file *my_file)

printk("release 函数调用成功\\n");

return 0;



//读函数

static ssize_t tiny4412_read (struct file *my_file, char __user *buf, size_t count, loff_t *loff)

printk("read 函数调用成功\\n");

return count;



//写函数

static ssize_t tiny4412_write(struct file *my_file, const char __user *buf, size_t count, loff_t *loff)

printk("write 函数调用成功\\n");

return count;



//虚拟文件操作集合

static struct file_operations tiny4412_ops=

.open=tiny4412_open,

.release=tiny4412_release,

.write=tiny4412_write,

.read=tiny4412_read

;




int dev_id;

int dev_dsp_id;


static int __init tiny4412_sound_module_init(void)


注册dsp设备*/

dev_dsp_id=register_sound_dsp(&tiny4412_ops,-1);


/*注册声卡设备*/

dev_id=register_sound_mixer(&tiny4412_ops,-1);


if(dev_id<0)

声卡设备注册失败!\\n");

else

printk("声卡设备注册成功!\\n");


return 0;



static void __exit tiny4412_sound_module_cleanup(void)

/*注销声卡设备*/

unregister_sound_mixer(dev_id);

unregister_sound_dsp(dev_dsp_id);

声卡设备注销成功!\\n");



//驱动初始化

module_init(tiny4412_sound_module_init);

module_exit(tiny4412_sound_module_cleanup);

MODULE_LICENSE("GPL");


DSP音频编码解码ioctl命令介绍

1.3.1 设置缓冲区大小

#define SNDCTL_DSP_SETFRAGMENT_SIOWR(P,10, int)


下面的代码示范了怎样设置声卡驱动程序中的内核缓冲区的大小:

int setting = 0xnnnnssss;

int result = ioctl(handle, SNDCTL_DSP_SETFRAGMENT, &setting);

if (result == -1)

perror("ioctl buffer size");

return -1;

1.3.2 设置声卡工作时的声道(channel)数目

根据硬件设备和驱动程序的具体情况,可以将其设置为0(单声道,mono)或者1(立体声,stereo)。下面的代码示范了应该怎样设置声道数目:

int channels = 0; // 0=mono 1=stereo

int result = ioctl(handle, SNDCTL_DSP_STEREO, &channels);

if ( result == -1 )

perror("ioctl channel number");

return -1;

if (channels != 0)

// 只支持立体声

1.3.3 设置声卡的采样格式

采样格式和采样频率是在进行音频编程时需要考虑的另一个问题,声卡支持的所有采样格式可以在头文件soundcard.h中找到,而通过ioctl系统调用则可以很方便地更改当前所使用的采样格式。下面的代码示范了如何设置声卡的采样格式:

int format = AFMT_U8;

int result = ioctl(handle, SNDCTL_DSP_SETFMT, &format);

if ( result == -1 )

perror("ioctl sample format");

return -1;

1.3.4 设置声卡的采样频率

在Linux下进行音频编程时最常用到的几种采样频率是11025Hz、16000Hz、22050Hz、32000Hz和44100Hz。下面的代码示范了如何设置声卡的采样频率:

int rate = 22050;

int result = ioctl(handle, SNDCTL_DSP_SPEED, &rate);

if ( result == -1 )

perror("ioctl sample format");

return -1;

1.3.5 mixer混音编程常用命令简介

声卡上的混音器由多个混音通道组成,它们可以通过驱动程序提供的设备文件/dev/mixer进行编程。对混音器的操作是通过ioctl系统调用来完成的,并且所有控制命令都由SOUND_MIXER或者MIXER开头,表1列出了常用的几个混音器控制命令:

名 称 作用

SOUND_MIXER_VOLUME 主音量调节

SOUND_MIXER_BASS 低音控制

SOUND_MIXER_TREBLE 高音控制

SOUND_MIXER_SYNTH FM 合成器

SOUND_MIXER_PCM 主D/A转换器

SOUND_MIXER_SPEAKER PC喇叭

SOUND_MIXER_LINE 音频线输入

SOUND_MIXER_MIC 麦克风输入

SOUND_MIXER_CD CD 输入

SOUND_MIXER_IMIX 回放音量

SOUND_MIXER_ALTPCM 从D/A 转换器

SOUND_MIXER_RECLEV 录音音量

SOUND_MIXER_IGAIN 输入增益

SOUND_MIXER_OGAIN 输出增益

SOUND_MIXER_LINE1 声卡的第1输入

SOUND_MIXER_LINE2 声卡的第2输入

SOUND_MIXER_LINE3 声卡的第3输入

1.3.6 常用设置示例

采样取值及请求宏(request):

采样频率:请求宏:SNDCTL_DSP_SPEED 值:48000

量化位数:请求宏:SNDCTL_DSP_SETFMT 值:AFMT_S16_LE

通道数 : 请求宏:SNDCTL_DSP_CHANNELS 值:单通道1,立体声2

void set_param(int fd)

int param;

printf("set params!\\n");

//----------------------------------

param = 48000;

ioctl(fd,SNDCTL_DSP_SPEED,¶m);

param = AFMT_S16_LE;

ioctl(fd,SNDCTL_DSP_SETFMT,¶m);

param = 2;

ioctl(fd,SNDCTL_DSP_CHANNELS,¶m);


参考资料

浅析ASoC-audio驱动oss框架下/dev/dsp与alsa框架下设备节点打开和创建简易流程

​http://blog.chinaunix.net/u2/70445/showart_2070710.html​


OSS--跨平台的音频接口简介

​http://bbs.lemote.com/viewthread.php?tid=20410​


(Open Sound System)是 unix 平台上一个统一的音频接口, 即只要音频处理应用程序按照OSS的API来编写,那么在移植到另外一个平台时,只需要重新编译即可。


OSS (Open Sound System)是unix平台上一个统一的音频接口。以前,每个Unix厂商都会提供一个自己专有的API,用来处理音频。这就意味着为一种Unix平台编写的音频处理应用程序,在移植到另外一种Unix平台上时,必须要重写。不仅如此,在一种平台上具备的功能,可能在另外一个平台上无法实现。但是, OSS出现以后情况就大不一样了,只要音频处理应用程序按照OSS的API来编写,那么在移植到另外一个平台时,只需要重新编译即可。因此,OSS提供了源代码级的可移植性。


同时,很多的Unix工作站中,只能提供录音与放音的功能。有了OSS后,给这些工作站带来了 MIDI功能,加上音频流、语音识别/生成、计算机电话(CT)、JAVA以及其它的多媒体技术,在Unix工作站中,同样可以享受到同Windows、 Macintosh环境一样的音频世界。另外,OSS还提供了与视频和动画播放同步的音频能力,这对在Unix中实现动画、游戏提供了帮助。


本文首先解释在音频编程时经常遇到的名词、设备文件的含义,然后分别在录音、播放、Mixer方面对OSS接口的使用方法进行介绍。由于OSS API十分丰富,因此在本文中只介绍那些最为常用的接口。对于OSS API的一个完整描述,可以参考[1]。


一、基础知识


数字音频设备(有时也称codec,PCM,DSP,ADC/DAC设备):播放或录制数字化的声音。它的指标主要有:采样速率(电话为8K,DVD为96K)、channel数目(单声道,立体声)、采样分辨率(8-bit,16-bit)。


mixer(混频器):用来控制多个输入、输出的音量,也控制输入(microphone,line-in,CD)之间的切换。


synthesizer(合成器):通过一些预先定义好的波形来合成声音,有时用在游戏中声音效果的产生。


在连接音频线时,一般是三芯或是四芯的,其中接左右声道的是啥线啊?

Qt之调用FFTW3实现音频频谱(实现)

单声道3W音频功率放大器:8002B

使用 Qt/Phonon 的多声道音频输入

单声道3W音频功率放大器:8002B

AliAGC 自动增益控制算法:解决复杂场景下的音量问题