这篇可以说是上一篇文章的对应。
这里还有一些问题值得思考:
* 延迟究竟是什么引起的?真的是封装的层次越多,延迟就越大吗?看看这篇:
* 最好看看原文后面的评论,也指出了原文的一些问题。
http://0pointer.de/blog/projects/pulse-glitch-free.html
原标题:State of sound in Linux not so sorry after all.
原文:http://insanecoding.blogspot.com/2009/06/state-of-sound-in-
linux-not-so-sorry.html
原作者:INSANE CODING
大约两年前,我写了一篇文章,题为“Linux声音
系统的可悲境地”(链接:
http://insanecoding.blogspot.com/2007 ... te-of-sound-in-linux.html ,
译文:) ,希望通过它让一些Linux下的声音问题修正。现在,两年过去了,很多东西都改变了,今天终于到了回顾Linux声音的现状的时间了。
上一篇文章的总结(怕你没看过):
* Linux下的声音系统的历史很有意思,以前,硬件缺乏的“混音”功能大多数由软件来补充。
* 人们创造了很多“声音”以便解决“混音”问题。
* 人们创造了很多“库”来解决后端太多的问题。
* 在Linux内核源代码中,ALSA替代了OSS v3,试图解决一些已有的问题。
* 闭源的OSS很好很强大。
* Linux发行版渐渐开始移除基于OSS的程序,以更好地向ALSA转移
* 一般的声音软件开发人员更喜欢简单的API。
* 可移植性是好东西
* 在某些情景下,用户会遭遇问题。
现在,很多东西都变了。比如:
* OSS再次开源和自由了。
* PulseAudio广为流传。
* 现有的库改进了。
* 新的Linux发行版发布了,有些已有的发行版试图重新设计它的整个声音软件栈,以改进用户体验。
* 人们读了我的上一篇文章,开始有了更多的认识,在某些方面,比以前更懂得开张圣听,察纳雅言。
* 我个人也更加深入地研究了这些问题,以便提供更详细的信息。
让我们拉近距离,观察一下OSS和ALSA现在的优势与不足。不是五年以前,不是去年,不是上个月,而是今天的它们。
首先,ALSA。
ALSA有三个组件组成。第一部分是内核中的程序。提供了API,以便另外两部分与之通信。第二部分是给声音开发者的API,这允许开发人员创造与 ALSA通信的程序。第三部分是混音组件,它可以放在另外两个组件之间,让多个使用ALSA API的程序同时输出声音。
为了便于理解,这里给出一幅图:
注意,图是我自己画的。我的艺术细胞很烂,我从来没有获过什么艺术奖。而且,这图也不是100%绝对准确的,但是已经足以让普通用户来了解其背后的大意了。
开发人员,想要在程序中输出声音,可以用以下任意一种方法:
* 通过ALSA API,直接输出到ALSA的内核API(当混音关闭时)
* 通过ALSA API,输出到“混音器”,混音器再输出到内核API(当混音关闭时)
* 用OSS v3的API直接输出到ALSA的内核API。
* 使用封装过的API,它们再利用上述3中方法输出。
可以看出,ALSA很灵活,具备OSSv3所不具备的混音功能,但是仍然为旧程序提供遗留的OSSv3支持。也允许关闭混音,以免某些情况下混音会造成声音质量下降,或者在某些时候引入用户所不希望的延迟。
两点很明确:ALSA提供可选的内核外的混音器,但ALSA的OSS遗留API不具备混音器。
其劣势也很明显,ALSA当初设计的目的是为了在比传统的“声音服务器”更低的层次,以较直接的方法,解决混音问题,
ALSA的明显优势是自由、开源、有混音器、可以支持多块声卡(这些OSSv3都不具备)。而且ALSA包含在内核中,而且迎合了新老程序的需求。
ALSA另一个不太明显的劣势是,它只支持Linux、FreeBSD、Solaris、Mac OS X和Windows上都没有。同样,一般的开发人员也觉得ALSA的本地API太难用了,但这值得商榷。
现在,看看今天的OSS。OSS现在的最新版是4,它与OSSv3完全不同。
与OSSv3的闭源不同,OSSv4是开源的,以GPL、3条款BSD和CDDL发布。
十年前,OSS在内核之内;新的OSSv4被踢出内核以外。因此,普通用户难以尝试之。旧的OSSv3缺乏混音,不支持多声卡,OSSv4不再是这样了。 很多讨论OSS,测试OSS,把OSS与ALSA比较的人,很不幸,用的是十年前的旧的OSS,因此,它们得出的结论都不是今天的现实。
这里有一幅OSSv4的图:
想要开发基于OSSv4的程序的开发人员应该按照以下某种方法做:
* 通过OSS API直接输出到内核,有混音
* 通过ALSA API输出到OSS API,有混音
* 通过封装库的API,间接利用上述某种方法
不像ALSA,当你用OSSv4的时候,最终用户总是能够得到混音。而且由于混音在内核内部,它不会引起像ALSA那么严重的延迟。
OSSv4提供了它自己的ALSA模拟层,但它非常糟糕,我还没有发现一个ALSA程序能够在OSS的ALSA模拟层上正常地跑。但是,这不是个大问题, 正如我刚才所说,ALSA自身的声音开发API就可以输出到OSS,这就达到了ALSA与OSS的兼容。你可以在这个链接中获得更多信息:
http://insanecoding.blogspot.com/2009 ... d-with-oss-version-4.html ALSA自身的库也能做到这一点。它的结构如下:
如你所见,它既能输出到OSS后端,又能输出到ALSA内核后端(下文还会继续讨论其他后端)。
由于基于OSS和ALSA程序都可以使用OSS或者ALSA内核后端,它们两者的差别也就很微小了(注意:我这里说的不是OSSv3),据我的研究和测试,它们的差别并不明显。
OSS总是提供混音;ALSA不是。
OSS的混音质量高于ALSA,因为OSS使用了更加精准的混音算法。
OSS的延迟小于ALSA,因为一切都在内核中运行。[译注:有人不同意这一点,认为延迟和缓冲区大小有关,而不是和程序运行于内核态、用户态有关。见本文开头的链接]
ALSA允许操作系统进入待机然后回复,然后原本正在播放的声音继续播放;OSS则不可以,要求应用程序重新开始播放。
OSS对于某些声卡来说是必须的,因为ALSA要么没有相应的驱动程序,要么质量很烂。
ALSA对于某些声卡来说是必须的,因为OSS要么没有相应的驱动程序,要么质量很烂。
ALSA被包含进Linux内核,很容易得到;OSS(v4)则没有。
现在,问题是,普通用户属于上述的哪一类呢?如果用户的声卡只能在其中一种系统上工作,很显然,他们就应该使用那个能够正常工作的。当然,用户也可以两者都试试,看看哪个工作得比另一个更好。
如果用户真的需要让他的程序在Linux待机、回复之后还能正常播放声音,那么,ALSA是(目前)唯一的选择。我个人不觉得这是个问题,我更怀疑到底有 多少Linux用户使用“待机”功能。Linux的待机功能很不怎么样,因为总有一些乱七八糟的硬件,比如网卡和显卡,把事情弄得更糟糕。
如果用户不想惹麻烦,ALSA是很明显的选择,因为它就包含在Linux内核里面。所以,用户用最新的ALSA比用最新的OSS更简单。但是,处理这些情况,应该是Linux发行版的工作。对于最终用户,切换ALSA和OSS应该是无缝而透明的。之后继续讨论该话题。
我们还发现,涉及到混音时,如果要选择一个混音质量和延迟都更好的选项,那么只要上述种种问题仍然存在,OSS都是更好的选择。但是,混音质量仅仅在音量更大的情况下变得明显,或者一些极个别情况下。而延迟问题仅仅在玩大型
游戏的时候才明显,听音乐,看电影的时候都不是问题。
等等,以上都是后端的问题。应用程序开发人员的API问题怎么样?
很多人都喜欢对各个API指指点点(我也喜欢,尤其是在我的上一篇文章中)。但是它们真的没有抓住本质。首先,下图是一般的声音封装API的结构图:
应用程序利用封装器——如OpenAL、SDL或libao——进行输出,然后,声音传到高层或低层的后端,而用户不用关心这一细节。
由于后端因操作系统声音接口而异,封装器允许用户编写一个程序,在Windows、Mac OS X、Linux上都能运行,而且更简单。
Adobe的人说这是一种问题(见
http://blogs.adobe.com/penguin.swf/2007/05/welcome_to_the_jungle.html ),使得在Linux下无法输出声音。没有比这种言论更远离事实的了。这种图(见以上连接)很误导人。OpenAL、SDL、libao、GStreamer、NAS、Allegro很多也都在Windows下出现,但我却从来没听说有人抱怨。
我也可以画一个类似的Windows下的图:
上图也是不完整的。还有XAudio和其他封装器,还有一些Windows特有的封装器,我只是忘了名字而已。
这也完全没有给任何人惹来麻烦,也不应该是个问题。
对于使用而言,库有如下几种:
OpenAL - 强大,难用,擅长“3D音频”。我参考了一些示例,只用了一两个小时,就做了很多事情,给我的程序加上了声音。
SDL - 简单,使用回调API,如果这种风格恰好和你的程序的风格是一致的,那么这是个不错的选择。我个人用了半小时就能给我的程序加入声音,但我不觉得这满足所有人的需求。
libao - 非常简单,难以置信地容易使用,但是,如果你的程序是非阻塞的,这就是个问题了。我只用了几分钟,就给我的程序加入了很多音响效果。我只是觉得,如果你的程序需要给声音单独创造一个线程,这有时候就有点烦了。同样,看你的需求。
我还没有尝试其他封装器,所以我不能评论它们,但是,同样的理念在每个里面都有体现。
当然,在Linux平台下有真正的OSS和ALSAAPI。那么既然还有更可移植、更易用的封装库,为什么还会有人去直接使用OSS和ALSA呢?这一般 都是对的,没有理由直接使用OSS和ALSAAPI来输出声音。某些情况下,使用封装API会引起额外延迟,你可能不期望。或者你并不需要封装的API提 供的更多高级功能。
下面是对OSS和ALSA API的总结:
OSSv3 - 易用,很多开发者都喜欢它,存在于各种UNIX,除了Mac OS X以外。我只用了10分钟就给我的程序加入了声音。
OSSv4 - 基本上和v3兼容,甚至更易用,存在于除了Mac OS X以外的任何UNIX上,在Linux上使用ALSA后端,具备重新采样功能,还有内置AC3解码器,我做了几个声音程序,每个也只要10分钟。
ALSA -难以使用,我所问过的大多数程序员都不喜欢它,文档烂,除了Linux以外哪里都没有它。但是有些程序员喜欢它,他们觉得ALSA提供了比OSSAPI 更高的灵活性。我个人花了3个小时才找到文档的头绪,并把声音加到程序中。然后,我发现声音只在我开发用的机器上可以工作,我又花了一个小时,看文档,改 代码,才让程序在两台机器上都能工作。最后,我发布了我的程序,又发现一些人抱怨我的程序在他们的机器上没有声音,又收到了几个别的开发人员发给我的补 丁。每个补丁都能让我的程序在他的机器上工作,但又让程序在我的某台机器无法工作。现在,一年已经过去了,我们的程序,在浪费了好多程序员好多个小时之 后,终于可以在所有的机器上工作了。不过,我真的不信任它。我们作为开发人员,不应该忙于这种问题。当然,你可以反对我,甚至引用例子说你是怎么找到文 档,快速实现声音,然后在所有的机器上经所有人测试都能够无瑕地工作。我也许只是太笨了。
我本以为OSS与ALSA之争是最终用户的事,也就是它们被迫使用某种框架。现在我知道,这与开发人员也息息相关。现在,主要问题很困难:如果我要利用 OSSv4所提供的所有的额外特性,我就必须使用OSS后端。而用户则根本不关心到底用哪个,除非它们使用能够利用这些特性的某些程序。
对于封装的API,我也用几个程序得到了一些有意思的结果:
App -> libao -> OSS API -> OSS Back-end - Good sound, low latency.
App -> libao -> OSS API -> ALSA Back-end - Good sound, minor latency.
App -> libao -> ALSA API -> OSS Back-end - Good sound, low latency.
App -> libao -> ALSA API -> ALSA Back-end - Bad sound, horrible latency.
App -> SDL -> OSS API -> OSS Back-end - Good sound, really low latency.
App -> SDL -> OSS API -> ALSA Back-end - Good sound, minor latency.
App -> SDL -> ALSA API -> OSS Back-end - Good sound, low latency.
App -> SDL -> ALSA API -> ALSA Back-end - Good sound, minor latency.
App -> OpenAL -> OSS API -> OSS Back-end - Great sound, really low latency.
App -> OpenAL -> OSS API -> ALSA Back-end - Adequate sound, bad latency.
App -> OpenAL -> ALSA API -> OSS Back-end - Bad sound, bad latency.
App -> OpenAL -> ALSA API -> ALSA Back-end - Adequate sound, bad latency.
App -> OSS API -> OSS Back-end - Great sound, really low latency.
App -> OSS API -> ALSA Back-end - Good sound, minor latency.
App -> ALSA API -> OSS Back-end - Great sound, low latency.
App -> ALSA API -> ALSA Back-end - Good sound, bad latency.
如果你觉得看懂上表很难,这里是总结:
* OSS后端总是产生高质量的声音,除了通过OpenAL->ALSA输出到OSS以外。
* ALSA使用OSS API,声音质量一般更好,而且延迟也更低(一般是因为它避免了所有的混音)
* 要获得更好的声音,用OSS相关技术都更好。
等等。“声音服务器”应该处于什么位置呢?
“声音服务器”最初创造的时候是为了解决OSSv3的混音问题。当代的声音服务器栈看上去是这样:
很显然,这些“声音服务器”什么也不干,纯粹增加延迟,应该完全扔掉。KDE4不再使用aRts声音服务器了,而是使用一个封装API,称为Phonon,它可以处理很多种后端(而其中某些后端也可以输出到声音服务器)。
但是,如上所述,ALSA的混音质量不如OSS高。而且ALSA缺乏一些很好的功能,比如可以为每个不同的应用程序设置对应的音量控制。
现在,你可以关掉ALSA低质量的混音器,而是让应用程序在输出声音之前,在内部通过改变声波,完成音量控制,但是这对开发人员来说不是很友好。
为此,Fedora和Ubuntu都引入了一个所谓的“最先进的”声音服务器,称为PulseAudio。
如果你还记得这幅图:
可以看出,ALSA的API也可以输出到PulseAudio。这就意味着,用ALSA的API写的程序可以输出到PulseAudio,并可以无缝地使 用PulseAudio的高质量混音器,而不用修改原有程序。PulseAudio也可以通过网络把声音发送到另一个远端的PulseAudio服务器 上。PulseAudio的栈看上去是这样:
可以看出,它非常复杂。而100%精确描述PulseAudio的细节的图将更复杂。
由于PulseAudio是如此的先进,绝大多数的封装API都能输出到PulseAudio。Fedora和Ubuntu也预装且为最终用户将其
配置好了。在某些情况下,它也可以接受为其他声音服务器书写的声音,如ESD,而不必在其上运行真正的ESD。这也就意味着,现在的很多程序发出的声音,在到达声卡之前,要经过很多很多层次。
有人认为,PulseAudio是我们新的救世主,为任何API书写的声音都可以输出到它上面,而且混音质量很好很强大。
例外的是,很多游戏玩家都抱怨PulseAudio增加了“奇大无比”的延迟,对于一些高端游戏来说,非常明显。用户不愿意在看到敌人和谐靠大家之后足足 3秒钟才听到和谐靠大家声。别听别人胡扯,声音服务器根本没用,尤其是在这么肥硕和复杂的结构下还想为游戏提供可以接受的低延迟。
与PulseAudio的龌龊相比,看看这个:
请你考虑考虑混音、逐程序音量控制、应用程序兼容性和其他特性,你觉得哪个声音栈更好?
没错,不要忘记应用程序。经常有人告诉我说它们的程序是为某个特定的API写的,因此他们要么用ALSA后端,要么用OSS后端。但是,正如我上文所述,任何一个API都可以输出到另一个后端上去,而它本身可以什么也不做。如果设置正确(见
http://insanecoding.blogspot.com/2009 ... d-with-oss-version-4.html ),你就算用新版的OSS播放Flash,也不会听不到声音。
那么,我们现在的情况是怎么样的呢?
最大的问题就是,我发现发行版根本就不考虑要不要让用户的选择更容易。
Debian和基于它的发行版提供一个“Linux sound base”包,允许用户选择使用OSS后端还是ALSA后端,而它本身什么也不做。以下是这样的
软件包应该提供的功能:
* 当用户选择OSS时,它应该
安装最新的OSS包,也要安装ALSA的“ALSA API -> OSS后端”的接口,并自动设置正确。
* 尽量少地配置一个安装好的OpenAL库,让它使用OSS后端,最好SDL、libao和其他封装库也这样配置
* 安装新应用程序或者封装库的时候,根据以上设置,配置它们,让它们也用OSS。
* 如果用户选择ALSA,则类似地配置,只不过反过来。
这样的设置将允许用户很容易地选择这两个后端。如果用户的声卡在发行版默认配置的后端上无法工作,这会很有用。如果用户关心,这也将允许用户客观地测试哪 个后端更好,而使用他们认为好的那一个。用户应该获得这样的权利。我个人认为OSS更好,但是,如果用户不喜欢默认的后端,我们应该允许用户选择。
我现在不断听到有人说:“但是,但是,OSS已经被踢出内核了,它也许再也不会被合并进来。”
让我们客观地分析这个问题。它有没有被包含进内核,真的很重要吗?就算KVM是内核的一部分,而VirtualBox不是,我们不是照样可以使用VirtualBox吗?就算KDE和GNOME都不是内核的一部分,我们不也可以使用它们吗?
最后,真正重要的是发行版的支持,而不是到底谁是内置的。谁关心内置不内置呢?唯一的区别在于,内核的开发人员不会去关心不包含在内核里的东西。但是这正是各大发行版正在做的工作,保证内核模块和相关的软件包在每个新的内核发布之后可以正常使用。
不管怎么样,总结几点:
我相信OSS比ALSA好,你倒是不见得同意。最好OSS和ALSA能够共享它们的驱动程序,而不是只支持某些声卡而不是另一些。
OSS应该支持系统挂起,以及其他比不过ALSA的特性,即使这些特性微不足道。这里有个建议:为什么Ubuntu雇用OSS的作者,并让它把最终用户最近遇到的一些问题弄得更友好一些呢?他现在正在找工作呢。(见
http://4front-tech.com/hannublog/?p=23 )然后再指派一些人改进现有的音量控制,让它对新的OSSv4更加友好,或者让HAL之类的东西默认就认识OSSv4。
问题应该直截了当地解决,而不是想PulseAudio那样绕弯,这个垃圾真该扔掉。如果用户真的需要远程音频,他应该很容易地把/dev/dsp映射到 NFS文件系统中,然后用这种方法输出到OSS。网络透明性应该在文件系统级别完成,这就是UNIX的设计理念(即:一切都是文件),而不是让那些非 UNIX的技巧在今天占领声音领域。
发行版们真的应该联合起来。虽然最近Draco Linux(见 )出现了,且只包含OSS的发行版;而
Arch Linux( )似乎把OSSv4视为头等公民,展示给用户,给用户选择,但是我已经告诉了它们,它们的ALSA兼容性部门没有给最终用户设置正确,这不好。而Arch Linux要求用户修改每个应用程序/库的配置文件。
由于OSS的操作系统抽象层,它的可移植性很好,与整个UNIX世界更加相关,而不像ALSA。FreeBSD则是采取自己的措施避免了OSS的抽象层,但还是基本上兼容的。如果愿意,用户可以在FreeBSD上安装官方版的OSSv4。
最后,Linux上的声音真的不需要那么可悲。发行版只要联合起来,阻止那些蔓延的指手画脚、宣传和“惧惑疑”论调,这些论调不是离题万里,就是根本错 误。让我们不要被Adobe公司、PulseAudio宣传机器以及其他人或组织冲昏了头脑。让我们客观一点,让我们应用最好的解决方案,不要以庸人自 居,也不要以五十步笑百步。