• Linux音频驱动简述


    一、数字音频

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

    数字音频系统通过将声波的波型转换成一系列二进制数据,来实现对原始声音的重现,实现这一步骤的设备常被称为模/数转换器(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位。

    量化位越高,信号的动态范围越大,数字化后的音频信号就越可能接近原始信号,但所须要的存贮空间也越大。

    声道数 

    声道数是反映音频数字化质量的还有一个重要因素,它有单声道和双声道之分。

    双声道又称为立体声,在硬件中有两条线路,音质和音色都要优于单声道,但数字化后占领的存储空间的大小要比单声道多一倍。

    二、声卡驱动

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

    眼下Linux下经常使用的声卡驱动程序主要有两种:OSSALSA

    ALSA和OSS最大的不同之处在于ALSA是由志愿者维护的自由项目,而OSS则是由公司提供的商业产品,因此在对硬件的适应程度上OSS要优于ALSA,它可以支持的声卡种类很多其它。

    ALSA尽管不及OSS运用得广泛。但却具有更加友好的编程接口,而且全然兼容于OSS,相应用程序猿来讲无疑是一个更佳的选择。

    三、Linux  OSS音频设备驱动

    3.1 OSS驱动的组成

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

    在声卡的硬件电路中,mixer是一个非常重要的组成部分,它的作用是将多个信号组合或者叠加在一起,对于不同的声卡来说,其混音器的作用可能各不同样。

    OSS驱动中。/dev/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之后。接下去就应该为其设置恰当的格式。然后才干从声卡读取或者写入数据。

    3.2 mixer接口

    int register_sound_mixer(structfile_operations *fops, int dev);

    上述函数用于注冊1个混音器,第1个參数fops即是文件操作接口,第2个參数dev是设备编号,假设填入-1,则系统自己主动分配1个设备编号。

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

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

    3.3 DSP接口

    int register_sound_dsp(structfile_operations *fops, int dev);

    上述函数与register_sound_mixer()类似,它用于注冊1个dsp设备,第1个參数fops即是文件操作接口,第2个參数dev是设备编号,假设填入-1。则系统自己主动分配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)。

    Linux OSS驱动结构例如以下图所看到的:

    3.4 OSS用户空间编程

    1、DSP编程

    DSP接口的操作一般包含例如以下几个步骤:

    打开设备文件/dev/dsp

    採用何种模式对声卡进行操作也必须在打开设备时指定,对于不支持全双工的声卡来说,应该使用仅仅读或者仅仅写的方式打开,仅仅有那些支持全双工的声卡,才干以读写的方式打开,这还依赖于驱动程序的详细实现。Linux同意应用程序多次打开或者关闭与声卡相应的设备文件,从而可以非常方便地在放音状态和录音状态之间进行切换。

    假设有须要,设置缓冲区大小

    执行在Linux内核中的声卡驱动程序专门维护了一个缓冲区,其大小会影响到放音和录音时的效果,使用ioctl()系统调用能够对它的尺寸进行恰当的设置。调节驱动程序中缓冲区大小的操作不是必须的,假设没有特殊的要求,一般採用默认的缓冲区大小也就能够了。

    假设想设置缓冲区的大小。则通常应紧跟在设备文件打开之后,这是由于对声卡的其他操作有可能会导致驱动程序无法再改动其缓冲区的大小。

    设置声道(channel)数量

    依据硬件设备和驱动程序的详细情况。能够设置为单声道或者立体声。

    设置採样格式和採样频率

    採样格式包含AFMT_U8(无符号8位)、AFMT_S8(有符号8位)、AFMT_U16_LE(小端模式,无符号16位)、 AFMT_U16_BE(大端模式,无符号16位)、AFMT_MPEG、AFMT_AC3等。使用SNDCTL_DSP_SETFMT IO控制命令能够设置採样格式。
    对于大多数声卡来说。其支持的採样频率范围一般为5kHz到44.1kHz或者48kHz。但并不意味着该范围内的全部连续频率都会被硬件支持,在 Linux下进行音频编程时最经常使用到的几种採样频率是11025Hz、16000Hz、22050Hz、32000Hz 和44100Hz。使用SNDCTL_DSP_SPEED IO控制命令能够设置採样频率。

    读写/dev/dsp实现播放或录音

    2. mixer编程

    声卡上的混音器由多个混音通道组成,它们能够通过驱动程序提供的设备文件/dev/mixer进行编程。

    对声卡的输入增益和输出增益进行调节是混音器的一个主要作用,眼下大部分声卡採用的是8位或者16位的增益控制器,声卡驱动程序会将它们转换成百分比的形式。也就是说不管是输入增益还是输出增益。其取值范围都是从0~100。

  • 相关阅读:
    PCL配置即常见问题
    opencv2.4.9配置+VS2013
    我的项目配置问题及解决
    Java 8 函数式编程
    leecode刷题(17)-- 实现StrStr
    leecode刷题(16)-- 字符串转换整数
    leecode刷题(15)-- 验证回文字符串
    博客迁移通知
    leecode刷题(14)-- 有效的字母异位词
    leecode刷题(13) -- 字符串中的第一个唯一字符
  • 原文地址:https://www.cnblogs.com/cynchanpin/p/6754021.html
Copyright © 2020-2023  润新知