10

我有一个应用程序,我在其中使用AudioTrack流模式播放动态生成的音频。该应用程序不必立即响应输入,因此延迟问题不会为程序的那一侧困扰我。

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

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

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

但是,仍有一些延迟getPlaybackHeadPosition()似乎无法解释因设备而异。

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

4

4 回答 4

5

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

按需轮询时间戳。

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

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

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

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

于 2016-06-04T02:37:02.777 回答
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){
}

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

于 2014-04-22T15:43:23.310 回答
-1

您应该考虑传递给 AudioTrack 创建的缓冲区大小。

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;
于 2013-09-10T13:25:01.957 回答
-1

好的,这是关键。首先,您需要扩展 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();
    }
}
于 2013-09-10T19:21:34.830 回答