如何获取精确的音频播放时间,或者如何构造一个和音频播放同步的时钟?
视频播放的时候需要解决音视频同步的问题,也就是播放到1:00的时候,放的画面也必须是1:00的画面。同样,很多游戏也需要画面和BGM配合起来,这就涉及到时钟同步的问题。
Windows下面获取时间的方法有很多种,包括系统时间接口(秒级误差)、timeGetTime(10ms量级误差),还有最精确的QueryPerformanceCounter(微秒级误差)。但这些方法都有个缺点,就是时间基准是以CPU或BIOS的时钟为准的(CPU时钟归根结底也是来自BIOS的晶振),而音频播放的时候,声卡会有板载时钟(输出的DAC的晶振),两个时钟之间可能有同步的问题,这就可能导致系统计时到5:00.00的时候,实际上音频只播放到4:59.9或者5:00.1,有个很小的偏差。
这个偏差一般可能无法察觉,但是如果播放一部一小时的电影,最后可能就会偏差秒的量级,会很明显;而对于游戏来说,像劲乐团、劲舞团之类的游戏,计时必须是和BGM精确匹配的,否则玩家就会感觉系统的判断跟音乐合不上拍。
最简单的获取音频播放时间的方法就是读当前的播放位置。DirectSound和XAudio2之类的音频播放接口都有查询当前播放位置的接口,不过这个接口返回的精度其实是比较低的。DirectSound据说在10ms左右,而我用XAudio2的相关接口测试,居然只有1/16秒的精度。这个精度对很多应用来说是不够的,游戏如果用这个为基准同步的话,最高就只有16fps的帧率,有明显的卡顿现象。
我现在用QueryPerformanceCounter和音频播放位置做了一个综合,每次用播放位置来修正当前时间,倒是还能用,不过时钟略微有点忽快忽慢(几ms到十几ms的量级)。不知道有没有什么更好的解决方案,或者有什么提供高精度播放位置的接口?