Linux音频分析 我们深入Linux内核来分析为什么Linux的声音这么糟糕

  • A+
所属分类:音频杂谈

Linux音频系统存在一个问题,这不仅仅是偶尔无法工作而已。真正的问题在于它过于繁杂了。

如果你坐下来在一张纸上试着画出那些在从一个音乐文件中读取音频信息,再从你的扬声器中播放出来这一过程中所用到的技术之间的关系的话,你就会很清楚地看到它就像打结的意大利面一样乱了。

这个问题的原因在于音频处理从本质上就要比其他的技术更复杂。声音从某个地方输入你的Linux电脑,又从另一个地方输出。如果我们画出一个用来描述将你的电脑和网络上其他的电脑连接起来的网络架构的OSI模型,我们看到的是分明的层次,每一层都有它自己的进程作用域和功能。

层与层之间很少有重合,因此你绝对不会碰到在第7层的最终用户进程和在第1层的原始比特流的电子脉冲相混淆的情况。

然而这种情况恰恰在Linux音频架构中存在。这个架构中甚至没有一个明确定义的最底层,各种音频技术在内核和你的硬件里各自为政。

和网络模型相比,Linux的音频结构更像是地壳,较低的层偶尔会爆发到表面,引发混乱痛苦,而较高的表面发生移动,取代原本是隐藏的根本技术。

比如Open Sound协议原本应该在内核层直接和你的硬件对话,但现在成了一个建立在ALSA上的复杂层。ALSA本身有一个内核层的堆栈和一个给程序员使用的更高级的API,用以将驱动程序和硬件属性配合起来播放环绕立体声或者处理MP3编码。

当大部分发行版把PulseAudio和GStreamer置于顶层时,你最终就得到了一个会发生像San Andreas错误这样的潜在破坏的不稳定的混乱系统。

ALSA
输入: PulseAudio, Jack, GStreamer, Xine, SDL, ESD
输出: Hardware, OSS

Maria von Trapp说过:“我们从最原始的地方开始吧。”要说起现代Linux音频,最原始的就是高级Linux声音结构,简称ALSA。

它和Linux内核挂接,为系统的其他部分提供音频功能。但它远远要比普通的内核驱动程序更有野心:它可以混合、对其它层提供兼容性、为程序员提供API,并且如同Windows和OS X平台的ASIO和CoreAudio一样作为一个非常底层而稳定的后台程序来运行。

ALSA本来是被设计用于取代OSS的。然而,多亏了ALSA的一个设计用于运行较老的只支持OSS的应用程序的兼容层,OSS并没有灭绝。把ALSA看成一个Linux声音系统的一个设备驱动层是最简便的方法。

你的音频硬件需要一个以“snd_”为前缀的交互式内核模块,而且必需能在任何事情发生时被加载运行。这就是你需要ALSA内核驱动来播放你系统会发出的任何声音,以及在有人想到发明一个这样的驱动程序之前你的笔记本沉默了这么久的原因。

幸运的是,大部分发行版都能自动设置你的设备和模块。ALSA负责把你的音频硬件的功能翻译给软件API,你的系统的其他部分通过它来操作声音。它被设计用于处理OSS(和当时其他大部分的声音驱动)的许多缺陷,其中最值得一提的就是同一时刻只有一个应用程序可以访问硬件的问题。

这就是为什么ALSA中的一个软件组件需要管理音频请求并了解你的硬件能力。比如你想要在用Amarok听音乐的时候玩游戏,ALSA需要获取这两条音频流,在软件中将他们混合起来,或者用你的声卡上的硬件混音器达到同样的效果。

ALSA也可以同时管理8个音频设备,有时还可以处理硬件上的MIDI功能,虽然这取决于你的硬件的音频驱动的规格,而且这一点随着计算机能力的增强而不那么重要了。

ALSA不同于典型的模块/设备驱动程序的地方正是它部分可定制性的原因。这里也正是Linux音频系统开始变得复杂了的地方,因为你可以通过创建你自己的设置文件来对你的ALSA设置作几乎任何的修改——从音频流如何混合和输出到取样率、比特深度及实时效果。

ALSA相对的透明性、高效性和灵活性让他成为了Linux音频系统的标准,也成为了几乎其他所有的音频架构为了和音频硬件交互而必须通过的层。

PulseAudio 
输入: GStreamer, Xine, ALSA
输出: ALSA, Jack, ESD, OSS

如果你认为让ALSA在后台安稳地运行,事情就会变得简单,那你就大错特错了。ALSA虽然能处理你的电脑输入和输出音频的具体细节,但你必须操作另一个复杂的层。

Linux音频分析 我们深入Linux内核来分析为什么Linux的声音这么糟糕

这就是PulseAudio——致力于连接硬件和软件功能、本地和远程计算机和音频流内容之间的隔阂。它像ALSA处理多个声卡一样处理网络上的音频,而且已经因为它的灵活性而成为了许多Linux发行版的一种标准了。

就像ALSA一样,这种灵活性伴随着复杂程度,但PulseAudio的问题更严重,因为它的面向用户性更强。这表示普通用户更容易弄乱它的网络。大部分发行版对它的设置敬而远之:以最新的Ubuntu发行版为例,你甚至可能不会发现PulseAudio被安装了。

如果你点击混音器小工具来调整你的声卡的音频等级,你会看到ALSA面板,但你真正看到的其实是一个虚拟设备——通过ALSA进入PulseAudio,再回到ALSA。

乍一看,PulseAudio似乎并没有给Linux音频系统增加任何新东西,因此它也受到了不少反对的呼声。虽然它并没有简化我们已有的东西,也没有让音效更强劲,但它确实增加了几个重要的特性。它也是一个Linux音频应用程序的全能层,不管它们各自的功能和你的硬件的规格如何。

如果所有的应用程序都是用PulseAudio,事情就简单了。开发者不需要考虑其他复杂的系统,因为PulseAudio带来了跨平台的兼容性。不过这也是之所以有这么多其他的音频解决方案的主要原因之一。

和ALSA不同,PulseAudio可以在多个操作系统中运行,包括其他的POSIX平台和微软的Windows。也就是说如果你建立一个是用PulseAudio的应用程序而非ALSA,把这个应用移植到另一个平台会很容易。

但是ALSA和PulseAudio之间有着一个符号链接,这是因为在Linux系统下,后者依赖于前者。PulseAudio将自己作为一个连接到ALSA的虚拟设备进行配置,就像任何其他的硬件一样。这就让PulseAudio更类似于Jack,因为它处于ALSA和桌面之间,来回透明地输送数据。

它也有它自己的术语。比如沉降(sink),指最后的目标。这些可以是网络中另一台计算机,也可以是你在虚拟ALSA中的声卡的音频输出。PulseAudio中完成这些沉降(sink)工作的部分被称为“源”(source)——例如你系统中的典型音频生成应用程序、你的声卡的音频输入,或者一段从另一台PulseAudio计算机中传来的网络音频流。

和Jack不同,应用程序不直接添加和删除源(source),于是你能对每段流作更好的控制。比如,通过PulseAudio混音器你可以调节每一个通过PulseAudio的应用程序的相对音量,不管那个应用是否有它自己的音量调节器。这在屏蔽那些吵人的网站时很好用。

GStreamer 

输入: Phonon
输出: ALSA, PulseAudio, Jack, ESD

有了GStreamer以后,Linux音频系统就开始变得越发混乱了。这是因为,和PulseAudio一样,GStreamer似乎没有给混音器增加什么新的东西。它是一个新的多媒体架构,并且在PulseAudio发布的数年前就有数量庞大的开发者,特别是在Gnome桌面下。

它是在Linux桌面下安装使用合适的解码器的少数方案之一。他也是GTK开发者的音频架构的选择,你甚至可以找到一个版本专门为Palm Pre处理音频。

GSteamer在音频层中插入在PulseAudio(它在大部分发行版都靠它实现音频输出)之上,应用程序之下。GStreamer很独特,因为它不仅是设计用于音频的——它通过插件可以支持多种流媒体格式,包括视频。

例如MP3播放,通常是通过下载一个附属于GStreamer插件的额外编码器来安装在你的系统中的。在Linux下唯一官方授权的商业版的Fluendo MP3解码器,是一个GStreamer插件,而它其它适配的编码器,包括MPEG-2、H.264和MPEG也都是这样

Jack 

输入: PulseAudio, GStreamer, ALSA,
输出: OSS, FFADO, ALSA

纵然PulseAudio有着开放设置的优点,它们在应用程序之间传递音频,最终还是会直接在输出端处理。Jack却是个中间层——音频和程序的远程进程信号等同,这使得音频应用程序得以通过各种组件建立。

Linux音频分析 我们深入Linux内核来分析为什么Linux的声音这么糟糕

最好的例子就是虚拟录音室,这样一个应用程序要能够抓取音频数据,同时对音频作效果处理,最后把得到的音频流通过一个主处理器准备发布。一个真实的录音室可能需要一个电缆网路,有时成为jack,来建立这些连接。而Jack就是在软件中做这件事情的。

Jack是“Jack音频连接工具”的简称。它的设计方向是低潜伏期的,这就是说音频上不会有过多的处理工作而拖慢它的进度。但是为了让Jack发挥全力,音频应用程序必须专门设计以使用Jack连接。因此,它不像ALSA和PulseAudio那样可以简单地替换,而且需要在另一个生成声音、提供物理输入的系统的顶端运行。

在大部分兼容Jack的应用程序中,你可以随意自由更换音频和输入的方式。比如你可以从VLC的输出直接传送到Audacity中,在播放过程中将这段音频流录制下来。或者你可以通过JackRack这样一款让你能建立包括ping延迟、多道混响和语言编码等多种实时效果的应用程序来发送它。

它的多才多艺对于数字音频工作站来说真是太奇妙了。比如Ardour使用Jack处理内部和外部的连接,而Jamin主处理器只能成为Jack处理器链中的一环。它就等于完全掌握了你的工作室的布线。它在Linux桌面上的成就如此辉煌,以至于你能看到它在OS X上一展才华。

FFADO 
输入: Jack
输出: Audio hardware

在专业和半专业音频的世界里,许多音频接口通过一个FireWire接口连接到他们的主机上。

这一方案有多个优点。FireWire速度很快,而且设备可以通过总线供电。许多笔记本和桌面计算机都有未经修改的FireWire接口,而标准的接口具有稳定性,也最成熟。你也可以在路上通过笔记本使用FireWire设备实现远程录音,回到工作室以后再把它们导入你的桌面计算机中。

但和USB有一个不需要额外驱动程序就可以处理音频的标准不同,FireWire音频接口需要它们自己的驱动。FireWire接口的这一复杂性使得建立一个ALSA接口不那么简单,所以它们需要它们自己的层。

原本这项工作有一个叫FreeBOB的项目。这个项目利用了许多FireWire音频设备都是基于相同的硬件这一优势。FFADO是FreeBOB的继承者,它对多种其他类型的FireWire音频接口开放驱动平台。

2009年末它发布了2代,包括了对许多类似Alesis、Apogee、ART、CME、Echo、Edirol、Focusrite、M-Audio、Mackie、Phonic和Terratec的单元的支持。因为设备能否工作实在是个未知数,所以你需要在购入之前好好检查一下,不过很多的厂商都通过向驱动程序开发者提供设备用以使用和测试来协助驱动程序的开发。

FFADO另一个优秀的特性是一些硬件的DSP特性被移植到了驱动程序中,整合了一个图形化的混音器来控制不同输入输出的平衡。这和ALSA混音器不同,因为它让音频流能够在第0层被硬件控制。

不同于其他的音频层,FFADO只会在Jack和你的音频硬件中切换。它没有给PulseAudio或者GStreamer提供后门,除非你用他们取代Jack。这使得你无法将FFADO作为一个播放音乐或者电影的通用音频层,要么你就要做好因为安装过程和Jack而搞得一团乱的准备。不过这也让驱动程序不会因为支持各种不同的接口而难以控制,特别是因为大部分专业音频应用程序都默认支持Jack。这使得它成为了工作室环境的一个最好的选择。

Xine 
输入: Phonon
输出: PulseAudio, ALSA, ESD

下面我们要进入Linux音频系统的生态地质学。Xine有点像下面的白垩纪:它是许多其他的音频层被冲刷后遗留下来的成果。大多数用户会在非常强大的DVD影片和媒体播放器中发现这个名字,虽然它很老了,但大部分发行版依然捆绑着它,而这正是Xine长盛不衰的关键。

Xine被开发出来的时候,开发者将它分成两部分,后端库用于处理媒体,前端应用程序处理用户交互。库凭借它能播放数不胜数的封装类型,包括AVI、Matroska和Ogg以及它们包含的数十种格式,例如AAC、Flack、MP3、Vorbis和WMA。

它通过借用许多其他的库来实现这一能力。因此,Xine可以作为开发者的全能架构,不需要考虑专利解码器的版权就能提供最大程度的文件兼容性。

Xine可以再输出端和ALSA与PulseAudio交互,也有不少应用程序能直接和Xine交互。最主流的有Gxine前端和Totem,而且Xine也是KDE的Phonon的默认后端,所以你在从Amarok到Kaffeine的各种应用程序中发现它被捆绑在一起。

Phonon 
输入: Qt and KDE applications
输出: GStreamer, Xine

Phonon的设计目的是通过移除一些系统中多余的繁杂性来简化开发者和用户的工作。它以KDE 4的应用程序的一个抽象的音频层开始起家,后来人们发现这个主意不错,于是Qt开发者将它直接插入KDE本身所基于的Qt架构中,制作了他们自己的Phonon。

它在跨平台应用程序的开发者中有很大的优势。它使得开发者可以用Qt在Linux上编写一个音乐播放器再简单地重编译给OS X和Windows使用,而不需要考虑音乐会被如何播放、使用的音频硬件的兼容性如何,或者最终操作系统会如何处理音频这些问题。例如把音频传送到OS X的CoreAudio的API中,或者Windows的DirectSound中,这些都会由Qt和Phonon自动完成。

在Linux平台(不同于早先版本KDE的Phonon),Qt的Phonon将大部分它所支持的透明的编码器的音频传送到GStreamer中。Phonon支持在不知不觉中从Qt架构中被分离。

这个系统有许多的批评,最主要的是它太过简单了,没有提供任何新的技术,不过看样子在KDE 4的周期里,KDE还是会将它保留在架构中。

其他分支

还有许多其他的音频技术,包括ESD、SDL和PortAudio。ESD是声音启发守护进程(Enlightenment Sound Daemon),它在很长的一段时间里是Gnome桌面的默认声音服务。后来,Gnome开始使用libcanberra(它本身可以和ALSA、GStreamer、OSS和PulseAudio交互),ESD在2009年4月不得不被废弃。

同样的事情发生在KDE的ESD上,虽然它并没有被广泛支持,而且似乎引发的问题要比它解决的更多。大多数人现在已经转移到KDE 4,所以它再也不被提及了。

在另一方面,SDL依然作为用于开发上百款跨平台游戏的SDL库的音频输出组件而生生不息。它支持大量的特性,并且成熟而稳定。

PortAudio是另一个跨平台音频库,它把SGI、Unix和Beos加入到可能的终端混音器中。使用PortAudio的最知名的应用程序就是Audacity音频编辑器了,这也导致它有时无法预计声音输出,Jack支持也有问题。

接着谈到OSS,开放声音系统(Open Sound System)。在2.4版本内核之后它就不再是一个核心Linux音频技术了,但这并不动摇它的存在。部分原因是有太多的老应用程序依赖于它,而且不像ALSA,它可以在Linux以外的系统上运行。它甚至还有个FreeBSD版本。

放在1992年,它是一个很好的系统,但是它几乎总是被建议用ALSA替换。OSS定义了Linux下音频如何工作,特别是音频设备要通过ioctl分支访问,例如通过/dev/dsp。

ALSA提供了一个OSS兼容层来让那些使用OSS的老应用程序避免放弃当前的ALSA标准。OSS项目作过开源和专利开发的尝试,现今仍作为4项前端技术(4 Front Technologies)的商业尝试继续开发着。在2009年11月发布了OSS 4.2的2002版。released in November 2009.

-------------------------------------------------------------------------------------------------------

原稿刊登于Linux Format第130期

 

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: