一、数字音频 1. 采样频率 2. 量化位数 3. 声道数 二、声卡驱动 出于对安全性方面的考虑,Linux下的应用程式无法直接对声卡这类硬件设备进行操作,而是必须通过内核 提供的驱动程式才能完成。在Linux上进行音频编程的本质就是要借助于驱动程式,来完成对声卡的各种操 作。 对硬件的控制涉及到寄存器中各个比特位的操作,通常这是和设备直 接相关并且对时序的需求非常严格,如果这些工作都交由应用程式员来负责,那么对声卡的编程将变得异常复杂而困难起来,驱动程式的作用正是要屏蔽硬件的这些底层
ALSA
三、编程接口 怎么对各种音频设备进行操作是在Linux上进行音频编程的关键,通过内核提供的一组系统调用,应用程式能够访 问声卡驱动程式提供的各种音频设备接口,这是在Linux下进行音频编程最简单也是最直接的方法。 3.1 访问音频设备 无论是OSS还是ALSA,都是以内核驱动程式的形式运行在 Linux内核空间中的,应用程式要想访问声卡这一硬件设备,必须借助于Linux内核所提供的系统调用(systemcall)。从程式员的角度来说,对声卡的操作在非常大程度上等同于对磁盘文件的操作:首先使用open系统调用建立起和硬件间的联系,此时返回的文件描述符将作为随后操作的标识;接着使用read系统调用从设备接收数据,或使用write系统调用向设备写入数据,而其他所有不符合读/写这一基本模式的操作都能由ioctl系统调用来完成;最后,使用close系统调用告诉Linux内核不会再对该设备做进一步的处理。 open系统调用 read系统调用 write系统调用 size_t write(int fd, const char *buf, size_t count); 系统调用write和系统调用read在非常大程度是类似的,差别 只在于write是向声卡写入数据,而read则是从声卡读入数据。参数fd同样是设备文件的标识符,他也是通过之前的open系统调用获得的;参数buf是指向缓冲区的字符指针,他保存着即将向声卡写入的数据;参数count则用来限定向声卡写入的最大字节数。如果write系统调用成功完成,他将返回向声卡实际写入的字节数;如果read系统调用失败,他将返回-1,同时还会设置全局变量errno,来指明是什么原因导致了错误的发生。无论是read还是write,一旦调用之后Linux内核就会阻塞当前应用程式,直到数据成功地从声卡读出或写入为止。 ioctl系统调用 int ioctl(int fd, int request, ...); 参数fd是设备文件的标识符,他是在设备打开时获得的;如果设备 比较复杂,那么对他的控制请求相应地也会有非常多种,参数request的目的就是用来区分不同的控制请求;通常说来,在对设备进行控制时还需要有其他参数,这要根据不同的控制请求才能确定,并且可能是和硬件设备直接相关的。 close系统调用 int close(int fd); 参数fd是设备文件的标识符,他是在设备打开时获得的。一旦应用程式调用了close系统调用,Linux内核就会释放和之相关的各种资源,因此建议在不必的时候尽量及时关 闭已打开的设备。 对于Linux应用程式员来讲,音频编程接口实际上就是一组音频设备文件,通过他们 能从声卡读取数据,或向声卡写入数据,并且能够对声卡进行控制,设置采样频率和声道数目等等。 /dev/sndstat
声卡驱动程式提供的/dev/dsp是用于数字采样(sampling)和数字录音(recording)的设备文件,他对于Linux下的音频编程来讲非常重要:向该设备写数据即意味着激活声卡上的D/A转换器进行放音,而向该设备读数据则意味着激活声卡上的A/D转换器进行录音。目前许多声卡都提供有多个数字采样设备,他们在Linux下能通过/dev/dsp1等设备文件进行访问。DSP是数字信号处理器(Digital Signal Processor)的简称,他是用来进行数字信号处理的特别芯片,声卡使用他来实现模拟信号和数字信号的转换。声卡中的DSP设备实际上包含两个组成部分:在以只读方式打开时,能够使用A/D转换器进行声音的输入;而在以只写方式打开时,则能够使用D/A转换器进行声音的输出。严格说来,Linux下的应用程式要么以只读方式打开/dev/dsp输入声音,要么以只写方式打开/dev/dsp输出声音,但事实上某些声卡驱动程式仍允许以读写的方式打开/dev/dsp,以便同时进行声音的输入和输出,这对于某些应用场合(如 在从DSP设备读取数据时,从声卡输入的模拟信号经过A/D转换器变成数字采样后的样本(sample),保存在声卡驱动程式的内核缓冲区中,当应用程式通过read系统调用从声卡读取数据时,保存在内核缓冲区中的数字采样结果将被复制到应用程式所指定的用户缓冲区中。需要指出的是,声卡采样频率是由内核中的驱动程式所决定的,而不取决于应用程式从声卡读取数据的速度。如果应用程式读取数据的速度过慢,以致低于声卡的采样频率,那么多余的数据将会被丢弃;如果读取数据的速度过快,以致高于声卡的采样频率,那么声卡驱动程式将会阻塞那些请求数据的应用程式,直到新的数据到来为止。 在向DSP设备写入数据时,数字信号会经过D/A转换器变成模拟信号,然后产生出声音。应用程式写入数据的速度同样应该和声卡的采样频率相匹配,否则过慢的话会产生声音暂停或停顿的现象,过快的话又会被内核中的声卡驱动程式阻塞,直到硬件有能力处理新的数据为止。和其他设备有所不同,声卡通常不会支持非阻塞(non-blocking)的I/O操作。 无论是从声卡读取数据,或是向声卡写入数据,事实上都具有特定的格式(format),默认为8位无符号数据、单声道、8KHz采样率,如果默认值无法达到需求,能通过ioctl系统调用来改动他们。通常说来,在应用程式中打开设备文件/dev/dsp之后,接下去就应该为其设置恰当的格式,然后才能从声卡读取或写入数据。
/dev/audio 由于设备文件/dev/audio主要出于对兼容性的考虑,所以在新研发的应用程式中最佳不要尝试用他,而应以/dev/dsp进行替代。对于应用程式来说,同一时刻只能使用/dev/audio或/dev/dsp其中之一,因为他们是相同硬件的不同软件接口。 /dev/mixer 输入混音器负责从多个不同的信号源接收模拟信号,这些信号源有时也被称为混音通道或混音设备。模拟信号通过增益控制器和由软件控制的音量调节器后,在不同的混音通道中进行级别(level)调制,然后被送到输入混音器中进行声音的合成。混音器上的电子开关能控制哪些通道中有信号和混音器相连,有些声卡只允许连接一个混音通道作为录音的音源,而有些声卡则允许对混音通道做任意的连接。经过输入混音器处理后的信号仍然为模拟信号,他们将被送到A/D转换器进行数字化处理。 输出混音器的工作原理和输入混音器类似,同样也有多个信号源和混音器相连,并且事先都经过了增益调节。当输出混音器对所有的模拟信号进行了混合之后,通常还会有一个总控增益调节器来控制输出声音的大小,此外更有一些音调控制器来调节输出声音的音调。经过输出混音器处理后的信号也是模拟信号,他们最终会被送给喇叭或其他的模拟输出设备。对混音器的编程包括怎么设置增益控制器的级别,及怎样在不同的音源间进行转换,这些操作通常来讲是不连续的,而且不会像录音或放音那样需要占用大量的计算机资源。由于混音器的操作不符合典型的读/写操作模式,因此除了open和close两个系 统调用之外,大部分的操作都是通过ioctl系统调用来完成的。和/dev/dsp不同,/dev/mixer允许多个应用程式同时访问,并且混音器的设置值会一直保持到对应的设备文件被关闭为止。 /dev/sequencer
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/38994/showart_525779.html |