一切都是为了混音
声音服务器, pulseaudio, pipewire, Windows Audio, AudioFlinger, oss4, jack, esd 等等,最主要的目的,就是混音。
对于消费级声卡,基本上不支持硬件混音。也就是同一时间只能让一个程序发声。
至于实际上你能听到多个程序发的声音,还能单独调节各个应用的声音大小,那都是因为用了声音服务器。声音服务器就一个嘛,就解决了同一时间只能让一个程序发声的问题。其他程序想发声,把数据交给声音服务器就好了。
但是大部分时候,用户只想听一个程序发声
其实,多个程序发声这个不是真正的需求,因为声音多了,就混乱了。用户大部分时候,只想听一个程序发声音。这个程序可以是电子游戏,可以是播放器,可以看 bilibili。 系统要只是混音,其实主要是为了处理一些 ”后台声音“ 。 比如 QQ 有消息的时候那 ”滴滴滴滴滴” 的提示。迅雷下完东西后那清脆的一声 叮。
采样率混战
声音系统,打出生以来,就没有一个全球普世的采样率标准。谁都可以自己决定采样率。 于是系统的来源声音,采样率是多种多样的。
但是,最终,只能有一个采样率,因为消费级声卡只能接受一个声音流。
所以声音服务器,要把各种采样率的声音都重新采样为声卡能接受的采样率,然后混音成一条音频流再输出。
但是,对现有的声音产品来说,最常见的来源是 MP3 和 MP4。前者是音乐,后者是(在线)视频。纯音乐的声音,通常是 44.1khz 采样率。而视频,尤其是 H26{4,5} 为代表的新视频,通常带的是 48khz 采样率的声音。
所以,消费级声卡为了照顾用户,通常会在硬件上提供 44.1khz 和 48khz 两套 ( 22.05khz 和 96khz 192khz 都是衍生采样率,所以是两套)采样率的支持。
播放 mp3 的时候,就让声卡的 DAC 进入 44.1khz 模式, 播放 mp4 的时候,就让声卡进入 48khz 的模式。
这样就可以避免重采样。
避免重采样
声卡都搞了2个晶振,就是为了软件不要重采样。结果,某些声音服务器啊,为了自己代码写起来方便,对应用交给他的声音,不管不顾的总是给重采样了。 过去 44.1khz 是主流的时候,他们就牺牲 48khz,后来 48khz 成了主流,他们就牺牲 44.1khz。
AudioFlinger 这种 java 佬写的垃圾,会这么搞也就算了。反正我不用 android。
但是你 号称是全新的 声音服务器的 pipewire 居然也学 AudioFliner ?
pulseaudio 的正确做法
既然大部分时候,用户只想听一个程序发声,那就应该尽量保证这个程序的声音不被重采样。除非声卡不支持。
比如你用 amarok 在播放 44.1khz 的 mp3。此时系统只有一个程序在播放声音。 pulseaudio 会把声卡配置为 44.1khz 采样率模式。然后声音数据基本直通给声卡。完全没有重采样,也没有混音。
突然,你点开了一个短视频,短视频的声音不太重要,所以你没有关闭 amarok, 只是把浏览器声音关小点。
这个时候, pulseaudio 会把浏览器传来的声音重采样成 44.1khz 然后和 amarok 混音,再输给声卡。
pulseaudio 牺牲了浏览器的声音质量。
一旦你停止播放 mp3. pulseaudio 又会把声卡切换到浏览器提供的采样率上。比如你看 bilibili 视频,那声卡就又切换到 48khz 采样率。
据我的观察,除了 pulseaudio , windows (至少在Windows 10 上)也是如此行为。都是为了避免无畏的重采样。
audioflinger 和 pipewire 的错误做法
audioflinger 不管应用程序给的是什么采样率的声音,都会在内部重采样成 44.1khz。然后坐混音,然后交给 HAL。
HAL 一般由 SoC 厂提供。HAL 拿到 44.1khz 采样率的声音,如果自己的 DAC 支持 44.1khz 那就直接输出。如果不支持,就再次重采样。
最糟糕的是,当你的播放器播放的是 SoC 本身支持的采样率的声音。但是 不是 audioflinger 内部的 44.1khz 那就要被毫无意义的重采样2次。
pipewire 不过是把这个写死的 44.1khz 变成了 默认 48khz 并且可在 /etc/pipewire/pipewire.conf 里修改的数值而已。
都知道 pulseaudio 的那个行为更好,音质更好,更省 cpu 更节能。但是它废程序员的脑子。
所以 pipewire/audioflinger 是不可能废程序员的脑子的。
既然开发者不想废脑子,那只能是垃圾了。
Comments