By 咣輝のま裔http://blog.sina.com.cn/s/blog_637d7cd80101pmwg.html
转载请注明作者信息,谢谢。

常常看到某些人给别人推荐ASIO,KS或者WASAPI的时候,总喜欢扯上一句:拥有更低的延迟,从而改善音质。
事实到底是不是这样的呢?让我们来看看Foobar2000作者的看法。
Note that low latency playback is relevant to real-time processing and editing only. It’s completely useless for music playback; in fact, higher latency is better in this case as it gives better protection against glitching from buffer underruns.
需要注意的是低延迟播放仅与实时处理和编辑相关。对于音乐播放是完全无用的。事实上,更高的延迟在这种情况下表现得更好。因为它提供了更好的保护,防止因为缓存欠载造成的毛刺。

作者这一两句话完全概括了重点,但是并不是所有人都能真正理解其中的道理。
低延迟的唯一好处:
低延迟的唯一好处仅在于录音播音的实时处理,比如将一个人说的话通过扩音器实时的广播,将播放的背景音乐与录制的人声进行实时混音处理等等对时间要求很高的操作。事实上低延迟是为了达到实时处理而不得不做的一种妥协。
什么是缓存欠载:
缓存欠载是指由于某种原因导致系统传输停顿使缓存不能及时补充有效数据,同时缓存中的数据又已被播放(录制)完,造成缓存中数据为空的现象。
为什么低延迟会造成缓存欠载:
实际上 延迟 = 采样点个数/采样率 + 偏移量 而多数情况下偏移量大致为0,于是多数情况下延迟 = 采样点个数/采样率 采样点个数反映了缓冲大小,缓冲大小决定了当前写入位置与播放位置的距离。
播放速度是固定的,如果缓冲大小为0,那么就必需时刻保持写入速度等于播放速度,这势必会造成系统频繁调用的高负载。当我们加入了缓冲机制,系统对于写入速度的要求就从瞬时速度降低为平均速度的水平。缓冲越大,对于突发高负载造成的写入速度降低的缓冲能力就越强。
(在播放的时候偏移量可以为负数,这样就实现了0延迟,让写入与播放同时进行,由于写入速度快于播放速度,而且播放的内容是可以预知的,这样就能够在预存了足够的采样点后,再保持速度同步。事实上不管是Foobar2000的WASAPI,还是ASIO,设置的都是缓冲大小。)
缓存欠载的后果:
根据处理方式的不同,缓存欠载会有两种后果:1. 禁音,短时间的禁音在人耳听来就是爆音的效果。2. 重复播放缓冲区,直到有新数据为止,这种处理方式在人耳听来就是一段很短的声音无限重播。

接下来要说些比较专业的话题了,如果你看不懂也没关系,大致看下,知道楼主的结论就好了。
让我们看看软件播放过程中的实际情况:
事实上,写入声卡缓冲的速度远快于播放的速度。为了不让线程在写完一个缓冲大小的数据后空载,增加不必要的消耗,有违节能环保的精神。于是每次在写入操作完成后进入睡眠状态(调用Sleep或者timeSetEvent+WaitForXXXX函数)。
菜鸟级程序员的做法:

菜鸟级程序员每次都让播放与写入同时开始,写完一个缓冲大小的数据后,便睡眠一个延迟的时间,等待播放完毕。然后又开始播放和写入,不停的重复下去。
这中做法并没有发挥出缓冲的所有优势,只能保证一个缓存大小中的声音是没有差别的。但是问题发生在两个缓冲的交汇处。睡眠并不能保证在精确的时刻被唤醒。每块缓冲大小的声音在时间上总是或多或少的前后漂移。一段1S的声音在100ms的延迟下,将有9处交汇处,在10ms的延迟下有99处交汇处,在1ms的延迟下有999次的交汇处。将延迟从100ms降低为1ms,对声音的影响加剧了100倍还不止,而系统频繁调用的次数也增加了100倍不止。
以下测试都在没有干扰的情况下进行:
20ms延迟的情况:

平均时间漂移(正负不抵消)体现了两个缓冲交汇处对音质的影响,累计时间漂移(正负不抵消)表示了这种处理方式下对于音质的总体影响,可以看到30S的声音就有381ms出现了问题。实际上,如果是日常的使用中,最大时间漂移可以轻易突破20ms。
200ms延迟下的对比:

可以看到加大延迟对于菜鸟写的播放程序有极大的好处,累计时间漂移(正负不抵消)直接从381ms降低到了20.9ms
配合双缓冲,循环播放,动态写缓存:

这种做法完全发挥出了缓冲的价值。只要最大时间漂移和累计时间漂移(正负抵消)不超过一个延迟的时间,就不会对音质产生影响。此时在前两项达标的情况下,平均时间漂移(正负不抵消)和累计时间漂移(正负不抵消)已经不会对音质产生影响。延迟越小,对于突发的高负载,抵抗能力就越差。
那么问题到这里就已经顺利解决了么?
我们知道不管Sleep也好还是timeSetEvent + WaitForXXXX,其时间精度都受到系统定时器分辨率的影响。系统默认情况下是15.6ms,Foobar2000 以及一些调用MMCSS (Multimedia Class Scheduler Service)的程序都会将定时器精度设置为10ms。然而这个值并不是你想设为多少就能设为多少的,这个值只能等于系统中所有程序设置的最小值,而且最高精度只能为1ms,这个值设的太小还会增加系统线程切换的消耗。
那么如果音频的延迟为25ms,在10ms的时间精度下,Sleep会如何表现呢:

结果就是每次都睡眠30ms。最终时间严重增长了5S。为了解决这个问题:
timeSetEvent + WaitForXXXX登场:

可以看到,在10ms的精度前提下,等待时间不断的在20ms和30ms间变化,实际上延迟25ms的表现还不如20ms,其对于突发高负载的承受力只有15ms的水平。在延迟足够大的情况下,这种方式足以解决简单Sleep带来的问题。
遗憾的是,系统定时器分辨率的精度最高只能是1ms,这就给不是整数毫秒的延迟带来了问题。
事实上,44100Hz在多数采样点下的延迟并不是整数毫秒。
WASAPI Event-Mode 对于采样点的限制如下:
最高500ms
大小不超过512KB
必需对齐到128Byte(是Byte不是bit)
拿20ms来说,实际上的延迟时间是20.3175ms 采样点896个,这多余的0.3175ms对于timeSetEvent + WaitForXXXX造成问题:

累计时间漂移(正负抵消)已经超过了延迟的20倍。这就是时间零头积累造成的问题。为了解决这个问题:
优化的Sleep – 最后的绝唱:
现在我们不再睡眠一个延迟值了,现在:
睡眠时间 = 当前循环次数n*延迟 - (当前系统时间 - 播放开始的系统时间)
这样便解决了零头时间带来的问题。

可以看到平均时间周期已经和延迟基本接近了,累计时间漂移(正负抵消)也得到了很好的控制,但是最大时间漂移超过了20ms,这不是偶然,实际上楼主测试了5次,其中4次都超过了20ms,1次为6ms。
在系统时间精度为10ms的前提下,想要在这种方式下良好工作,延迟至少要30ms。实际上这是Push-Mode下不得不采用的方式,只有这种方式才能解决上面提到的所有问题。Foobar2000便是这么做的。这也是其缓冲长度必需大于50ms的原因。虽说Foobar2000的缓冲长度与声卡的缓冲大小不是同一个事物,但两者前后承接,工作原理上极其相似。
(其实系统计数器的分辨率可以达到100纳秒的级别,但是用在播放器上完全是杀鸡用牛刀。100纳秒级别的计数器在大型游戏上常常用到)

WASAPI Event-mode来袭
只有降低两个缓冲区交接处的时间误差和漂移幅度,才能在音质不受损的情况下,降低延迟。
我们知道在当前系统时间精度下,为了保证音质不受损,延迟不可能降得太低。为了降低延迟,我们迫切的需要一种不需要高负载轮询,又能高度准确的时间。硬件驱动回调模式便由此孕育而生。不论是WASAPI Event-mode 还是KS又或者是ASIO,采用的都是这种方式。这才是他们的精髓所在。
声卡在每次播放完一个缓冲区后便发送事件通知程序,应用程序便开始将音频数据写入缓冲区。详细图解,请回头看上面的:配合双缓冲,循环播放,动态写缓存。
硬件驱动回调模式的唯一区别就是:现在不是由我们自己定时写入了,而是让硬件告诉我们什么时候该写入了。这便使得我们写入的时间相当准确,从而对于缓冲大小的要求降低,最后延迟就可以控制的更小。
现在楼主写的基于WASAPI Event-mode的测试播放器该登场了:

将你要播放的文件命名为a.wav放在同一目录下,然后运行程序就可以播放了。
只支持wav格式,只支持声卡硬件支持的格式,支持声卡选择。
文件采用全文件缓冲的方式载入,请确保拥有足够的空闲内存(事实上,楼主并不认为全文件缓冲会改善音质。只要声卡缓冲大小(延迟)足够大,全文件缓冲就没有任何意义。楼主这么做完全属于偷懒的做法)。
实际上WASAPI Event-mode的兼容性可能在不同的声卡下表现有所不同,楼主基于自己的声卡修正了24位音频文件的播放问题。如果在你的机器上播放24位音频格式时出现杂音,请留言反馈,楼主可以再发一个未修正的版本。
想要查看声卡支持的格式请使用楼主写的声卡参数测试软件:

还能顺便检查下最小延迟以及系统定时器分辨率。
以上两个软件基于WASAPI,不支持Windows XP系统。如果遇到问题,可以留言反馈。
如果Windows Vista以上系统无法运行,请安装Visual C++ 2010运行时组件
http://www.microsoft.com/zh-cn/download/details.aspx?id=8328
http://www.microsoft.com/zh-cn/download/details.aspx?id=13523
那么我们开始测试:

可以看到累计时间漂移(正负不抵消)减小到了原来的一半,虽然这没什么作用,但是也可以作为一个浮动的观察值。最重要的是,最大时间漂移降低到了2ms以下。可以说在系统单纯播放音乐,没有干别的事情时,5ms左右的延迟就已经完全足够了。
你还观察到累计时间漂移(正负抵消)为负数,实际上这是因为声卡的时钟与系统的时钟不同造成的。就好像两杆秤的1Kg不一样。如果以声卡的时钟为标准来衡量的话,误差应该很小,只是微妙级别。我前面已经说过了,只要累计时间漂移(正负抵消)的值小于延迟,就不会对声音造成任何影响。

空闲时的测试可以说是太轻松了,让我们做下压力测试吧:
在已运行极品飞车17的情况下,对一首6分30秒192000Hz 24bit的歌曲进行播放测试。
以下测试都做了3次以上,不存在突发情况造成的误差。
延迟2.25ms下的结果

点评:歌曲播放时间直接增加了11秒,最大时间漂移达到40.2ms,是延迟的18倍。这么低的延迟,不但严重影响了音质,还造成了线程频繁切换调用的高负载。楼主已无法忍受,直接丢掉了耳机,默默地开着车。
延迟20ms下的结果

点评:累计时间漂移(正负抵消)和最大时间漂移都超过了延迟,虽然不多,但还是对音质产生了一定的影响。显然至少要有50ms的延迟才能完全满足实际情况。
延迟200ms下的结果

点评:最大时间漂移降低到了1.6ms,由此可以看出对系统和声卡的压力降低了许多,更加稳定了。明显舒缓了许多,楼主开车头都不晕了,心情也不急躁了,当然这很有可能是心理安慰的作用,哈哈。
最大值:341.25ms下的结果

点评:与200ms相似的结果,完全在误差范围之内。进一步减轻了系统的负载,对突发事件也拥有了更强的抵抗能力。
楼主写的最后一个软件,也是前面一直用到的测试工具该登场了:

   多数选项对于你的来说意义不大,不过我还是要推荐下第6项(这个工具XP也能运行)

事实上我们无法明确知道Foobar2000等软件采用的缓冲写入算法究竟是否给力,但是我们可以通过计算,得出几个兼容性最好的延迟时间。
上面列出的便是44100Hz 16bit下最具兼容性的延迟。强烈推荐320ms,这是44100这个采样率能够获得的最小整数时间。
如果你希望一个较小的延迟的话,可以设置为50ms:

上面提到的3个工具的下载地址:
声卡检测工具+播放器+延迟测试工具
http://pan.baidu.com/share/link?shareid=3260973561&uk=1494056105
关于Foobar2000的设置建议:

其实正如Foobar2000作者所说的,只要缓冲足够大,便不会对音质产生多大影响。如果你追求完美的话就把缓冲长度设为320的整数倍,比如1280吧,理由我前面都说过了。
如果你喜欢WASAPI的话就在设备里选择上,然后在高级里这么设置:

本来Event-Mode的缓冲也应该设为320的。很可惜的是,作者写的event mode插件存在很严重的bug,导致延迟大于90ms左右便会声音播放错乱,严重缩短播放时间,这极有可能是WaitForXXXX函数超时时间设置过小造成的。所以我不推荐你用Event-Mode,我更倾向于使用320ms延迟的push mode(实际上push mode最大的缓冲时间能达到2000ms,作者限制为1000ms,估计是在内部做了双缓冲处理)。
线程优先级勾上MMCSS,模式输入Pro Audio,Pro Audio属于多媒体调度优先级最高的模式了。
全文件缓冲这个除了浪费内存,没有任何好处,按作者默认设置0就好:)

终于看完了,如果你觉得本文写的不错,看了之后有所收获,欢迎转载。

谈谈低延迟对音质的负面影响,顺便谈谈WASAPI相关推荐

  1. OPPO Enco Free真无线耳机:超低延迟高音质 智慧触控看得见

    据公开数据显示,苹果公司凭借AirPods系列,2019年这一单项业务收益突破60亿美元.真无线耳机作为一个蓝海市场,现在也出现了越来越多入局者.AirPods系列虽优秀,但并不代表它的防线坚不可摧. ...

  2. 小米air2se耳机只有一边有声音怎么办_2020高颜值游戏低延迟蓝牙耳机,高音质听声辨位非这五款蓝牙耳机莫属...

    随着各大手机厂商陆续取消耳机接口以及TWS技术发展普及,让TWS真无线蓝牙耳机在整个耳机市场是大放异彩,本来无线的佩戴体验就更适用于便捷高效的生活方式,再加上技术的突破,在信号以及音质上都有着质的飞跃 ...

  3. 高音质游戏无线蓝牙耳机推荐,低延迟吃鸡王者兼容无压力

    现在的真无线蓝牙耳机实在是太多了,目前我个人也基本上不使用有线耳机,毕竟无线耳机确实带来了更好的体验,尤其是在便携性和颜值上,真无线耳机确实比有线耳机出色.我相信很多人都跟我一样,都希望能够拥有一款性 ...

  4. 喜欢玩游戏怎么能少了这几款蓝牙耳机?高音质低延迟手游必备神器

    由于游戏耳机更注重游戏中声音的精准定位以及提供真实的临场感,注定了其在音乐的还原度和表现力上表现平平.那么游戏耳机真的就无法兼顾游戏和音乐?这可不一定.很多品牌蓝牙耳机都能做到音质与性能兼顾了,所以关 ...

  5. 有什么适合玩手游的蓝牙耳机?高音质低延迟吃鸡王者轻松驾驭

    目前大家对蓝牙耳机的要求越来越高了,而且手游的大肆风靡,让本来关注度不高的游戏蓝牙耳机逐渐开始受到了热捧,厂家更新产品的周期缩短.品类增多更能说明这个问题.而目前火热的电竞行业更是对这些外设产品起到了 ...

  6. 高清音质媲美HIFI,双11高性价比低延迟蓝牙耳机推荐

    随着技术的进步,我们更习惯于使用无线蓝牙耳机了,使用时不再受耳机线的约束,让我们无论运动通勤还是休闲娱乐都更方便.更享受.对于游戏方面免去了线材的束缚,玩得更尽兴,尤其是type-c充电口当道的时代, ...

  7. 手游高续航环绕立体音质蓝牙耳机,低延迟追剧画音同步不卡顿

    当前国内外手机厂商取消3.5mm耳机孔的普及,无线蓝牙耳机已经逐渐成为人们日常生活.办公和游戏的首选了,无线耳机不仅可以带来更为自由的听歌方式,同时不输于有线耳机的音质也受到了大多数用户特别是年轻人的 ...

  8. 学生党平价高音质蓝牙耳机分享,五款电竞爱好者最爱低延迟蓝牙耳机

    如今,蓝牙耳机市场的竞争越来越激烈,各大蓝牙耳机品牌也推出了很多新款式,不少人难免要问:蓝牙耳机什么牌子好呢?先不说大牌溢价严重,就算买了之后都得吃好久的土吧,丢了坏了更是心疼好长时间,对于预算不多的 ...

  9. 实时音视频聊天中超低延迟架构的思考与技术实践

    1.前言 从直播在线上抓娃娃,不断变化的是玩法的创新,始终不变的是对超低延迟的苛求.实时架构是超低延迟的基石,如何在信源编码.信道编码和实时传输整个链条来构建实时架构?在实时架构的基础之上,如果通过优 ...

最新文章

  1. 将GB28181国标流转成RTSP流
  2. ASP.NET三层架构之不确定查询参数个数的查询
  3. 各个图标的意思_冬奥体育图标设计团队负责人林存真:每一个图标要画100稿以上...
  4. Vue 基础的开发环境
  5. YOLOv4一作提出Transformer新架构:DPT!替代卷积网络做密集预测
  6. 几何画板椭圆九种画法_几何画板中椭圆的几种构造方法
  7. 如何查询网络出口IP
  8. 《增长黑客》学习总结
  9. python 绘制3D图
  10. 【技法操作】UI界面设计,用PS绘制定位app页面设计教程
  11. 计算机硬件工程师面试题集,硬件工程师笔试及面试问题
  12. java ?: 三目运算符
  13. unity3d 音频无缝循环
  14. 解决“Win 10 ipv6无网络权限/无Internet连接权限”问题
  15. Java 内部类详解
  16. “即刻搜索”为什么使用率几乎为零
  17. zabbix密码忘记怎么从mysql找回_zabbix 忘记密码,找回密码
  18. 利用easyUI实现tree叶子节点横向展示以及checkbox联级勾选改造
  19. 2018考研数学二答案真题解析.pdf
  20. 调查称多地10%大米镉超标 食物污染链持续多年

热门文章

  1. syn flood 攻击 c 语言源代码,以太网模拟syn flood攻击
  2. 在c语言求30角的正弦值,第1课时 正弦及30°角的正弦值
  3. 太极英语笔记-前传语法-代词
  4. 如何寻找创业合伙人、搭建创业团队?
  5. java专区软件_分享几款让你事半功倍的装机必备软件
  6. 免费展示自己写的HTML给别人看
  7. 程序员正确看代码的方式
  8. 一套用了 70 年的计算机架构 —— 冯·诺依曼架构
  9. cin和cout的使用
  10. avc水平什么意思_西方经济学中AVC是什么意识?