如何确定Android上的音频延迟(AudioTrack)?

jn_*_*pdx 10 java audio android audiotrack

我有一个应用程序,我使用AudioTrack流媒体模式播放动态生成的音频.该应用程序不必立即响应输入,因此延迟问题不会打扰我的程序的那一面.

问题是我有一个动画需要与音频尽可能精确地"同步",似乎不同的设备在AudioTrack停止阻止write()呼叫和要求更多数据之间有不同的时间量,并且从扬声器播放音频.

我目前的解决方案让我大部分都在那里 - 我计算AudioTrack到目前为止我传入的帧数,并将其与之进行比较getPlaybackHeadPosition().它看起来基本上像:

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

但是,仍然存在一些getPlaybackHeadPosition()似乎没有因设备而异的延迟.

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

jos*_*h42 5

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

按需轮询时间戳。

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

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

然后,您可以通过计算该特定帧写入的时间与AudioTrack实际getTimestamp()呈现的时间来确定延迟。我发现这种方法比上面提到的其他方法更准确。

不过你必须小心。文档说getTimeStamp()并非所有平台或所有路线都支持。您可以通过检查返回值来判断调用是否成功boolean。我发现在我测试过的设备上,该函数返回 false,直到音频开始呈现,然后后续调用返回 true。我只在AudioTrackinSTREAM_MUSIC模式下进行过测试。你的旅费可能会改变。


Poi*_*ull 2

考虑驱动程序的延迟。有隐藏函数 AudioManager.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){
}
Run Code Online (Sandbox Code Playgroud)

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

  • 还有另一个更准确的隐藏方法“AudioTrack.getLatency”,因为它存在于 AudioTrack 实例上,因此也可以考虑特定于硬件/路由的延迟。它可以通过反射以类似的方式调用:https://developer.amazon.com/docs/fire-tv/audio-video-synchronization.html#section1-2 (2认同)