你如何确定Android上的audio延迟(AudioTrack)?

我有一个应用程序,我在stream模式下使用AudioTrack播放dynamic生成的audio。 该应用程序不必立即对input作出响应,所以延迟问题不会影响到程序的这一方面。

问题是我有一个animation,需要与audio尽可能精确地“同步”,似乎不同的设备有不同的时间之间的时间之间的AudioTrack停止阻止write()调用,并要求更多数据,以及何时从扬声器播放audio。

我目前的解决scheme使我得到了大部分的方法 – 我计算了我已经传递给AudioTrack ,并将其与getPlaybackHeadPosition()进行比较。 它看起来基本上像:

 long currentTimeInFrames = 0; while(playingAudio) { currentTimeInFrames += numberOfFramesToWrite; long delayInFrames = (currentTimeInFrames - audioTrack.getPlaybackHeadPosition()); audioTrack.write(frameBuffer,0,sampleSize); doAnimationAfterDelay(delayInFrames); } 

但是, getPlaybackHeadPosition()仍然存在一些延迟, getPlaybackHeadPosition()延迟似乎没有考虑到因设备而异。

有没有办法轮询系统的AudioTrack的延迟?

Solutions Collecting From Web of "你如何确定Android上的audio延迟(AudioTrack)?"

考虑驱动程序的延迟。 有隐藏的functionAudioManager.getOutputLatency(int)来得到这个。

像这样调用它:

 AudioManager am = (AudioManager)getSystemService(Context.AUDIO_SERVICE); try{ Method m = am.getClass().getMethod("getOutputLatency", int.class); latency = (Integer)m.invoke(am, AudioManager.STREAM_MUSIC); }catch(Exception e){ } 

我在不同的设备上得到大约45 – 50毫秒。 在计算中使用结果。

API级别19在AudioTrack添加了一个名为getTimeStamp()的方法 。 从文档:

根据需求轮询时间戳。

如果您需要在初始预热期间或路由或模式更改后跟踪时间戳,则应定期请求新的时间戳,直到报告的时间戳显示帧位置正在前进,或直到明确此路由的时间戳不可用。

您指定一个AudioTimestamp对象作为函数的参数,它将填充最近“呈现”的帧位置以及“估计”时间戳(以纳秒为单位)。 纳秒值对应于SystemClock.uptimeMillis()返回的毫秒值。

然后,您可以通过确定何时将特定帧写入AudioTrack与何时getTimestamp()认为它实际显示来确定延迟。 我发现这种方法比上面提到的其他方法更准确。

你必须小心,虽然。 文档说getTimeStamp()不支持所有平台或所有路线。 您可以通过检查boolean返回值来确定调用是否成功。 我已经find了我testing过的设备,函数返回false,直到audio开始呈现,然后后续调用返回true。 我只在STREAM_MUSIC模式下用AudioTrack进行testing。 你的旅费可能会改变。

您应该考虑您传递到AudioTrack创build中的缓冲区大小。

 final int minBufSize = AudioTrack.getMinBufferSize(Application.PLAYRATE, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT); out=new AudioTrack(AudioManager.STREAM_MUSIC, Application.PLAYRATE, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT, minBufSize, AudioTrack.MODE_STREAM); extraLatencyFrames = minBufSize/4; 

好的,这是关键。 首先,您需要扩展Audiotrack类,然后使用getNativeFrameCount来近似处理事物本身的延迟。

 class MyAudioTrack extends AudioTrack { public MyAudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode) throws IllegalArgumentException { super(streamType, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes, mode); System.out.println("Native framecount "+getNativeFrameCount()); } public int getFrameCount() { return getNativeFrameCount(); } }