如何在 Android 上使用 AudioTrack.getTimestamp() 来计算延迟?

How to use AudioTrack.getTimestamp() on Android to calculate latency?

我看到许多资源建议在现代 Android 版本上使用 AudioTrack.getTimestamp() 来计算 audio/video 同步的音频延迟。

例如:

https://developer.amazon.com/docs/fire-tv/audio-video-synchronization.html#section1-1

https://groups.google.com/forum/#!topic/android-platform/PoHfyNK54ps

但是,其中 none 解释了 如何 使用时间戳来计算延迟?我正在努力弄清楚如何处理时间戳的 framePosition/nanoTime 来得出延迟数。

因此在此 API 之前,您将使用 AudioTrack.getPlaybackHeadPosition(),这只是一个近似值。因此,为了考虑延迟,您必须使用两种隐藏方法之一的延迟值来抵消该值:AudioManager.getOutputLatency()AudioTrack.getLatency().

使用新的 AudioTrack.getTimestamp() API,您可以在给定时间直接在输出处获取播放头位置的快照。因此,它是完全准确的,并且已经考虑了设备延迟。因此,现在无需调用任何其他 API 来达到 add/remove 延迟。

需要注意的是,这个时间戳只是一个快照,文档建议您不要经常调用这个新方法。所以获得 "current" 位置的技巧是使用你的最后一个快照并线性插值当前值应该是什么:

playheadPos = timestamp.framePosition + 
              (System.nanoTime() - timestamp.nanoTime) * samplerate / 1e9;

然后可以通过维护另一个每次 AudioTrack.write() 完成时递增的计数器,将此位置与您写入 AudioTrack 的帧数进行比较:

int bytesWritten = track.write(...);
writtenPos += bytesWritten / pcmFrameSize;

如果您正在使用 ENCODING_AC3AudioTrack 报告的播放头位置仍然是样本。您需要将其转换为字节,或者将您写入的字节数转换回样本。无论哪种方式,您都需要知道 AC3 流的比特率(即 384000bps

int bytesWritten = track.write(...);
writtenPos += bytesWritten * samplerate / (bitrate / 8);