AVAudioPlayerNode最后渲染时间

23

我在 AVAudioEngine 中使用多个 AVAudioPlayerNode 混合音频文件以进行播放。一旦所有设置都完成(引擎准备好、启动、音频文件分段安排好),我会在每个播放器节点上调用play()方法开始播放。

由于循环遍历所有播放器节点需要时间,因此我会获取第一个节点的lastRenderTime值的快照,并用它来计算节点play(at:)方法的开始时间,以保持节点之间的播放同步:

let delay = 0.0
let startSampleTime = time.sampleTime     // time is the snapshot value    
let sampleRate = player.outputFormat(forBus: 0).sampleRate
let startTime = AVAudioTime(
        sampleTime: startSampleTime + AVAudioFramePosition(delay * sampleRate),
        atRate: sampleRate)
player.play(at: startTime)

问题出在当前播放时间上。

我使用以下计算方法来获取该值,其中seekTime是我跟踪的值,以防我们寻找播放器。在开始时它的值为0.0

private var _currentTime: TimeInterval {
    guard player.engine != nil,
          let lastRenderTime = player.lastRenderTime,
          lastRenderTime.isSampleTimeValid,
          lastRenderTime.isHostTimeValid else {
        return seekTime
    }

    let sampleRate = player.outputFormat(forBus: 0).sampleRate
    let sampleTime = player.playerTime(forNodeTime: lastRenderTime)?.sampleTime ?? 0
    if sampleTime > 0 && sampleRate != 0 {
        return seekTime + (Double(sampleTime) / sampleRate)
    }
    return seekTime
}

虽然这产生了一个相对正确的值,但我能听到我演奏和我听到第一个声音之间的延迟。因为一旦我调用play(at:)lastRenderTime立即开始前进,并且必须有某种处理/缓冲时间偏移。

明显的延迟约为100毫秒,非常大,我需要精确的当前时间值来进行可视化渲染。

可能没有关系,但每个音频文件都是AAC音频,我在播放器节点中安排它们的段落,我不直接使用缓冲区。 段长度可能会有所不同。一旦我安排好音频数据,我还会在每个播放器节点上调用prepare(withFrameCount:)

所以我的问题是,我观察到的延迟是否是缓冲问题?(我的意思是,例如,我应该安排较短的片段),是否有一种方法可以精确计算此值,以便我可以调整当前播放时间计算?

当我在一个AVAudioPlayerNode上安装一个tap块时,该块被调用并带有一个长度为4410的缓冲区,采样率为44100 Hz,这意味着0.1秒的音频数据。我应该依赖此来计算延迟吗?

我想知道是否可以信任我在tap块中获得的缓冲区长度。另外,我试图计算我的音频图的总延迟。有人可以提供关于如何精确确定此值的见解吗?

1个回答

1

以下是来自苹果开发者论坛theanalogkid的帖子:

在系统中,延迟通过以下方式进行测量:

音频设备I/O缓冲帧大小 + 输出安全偏移量 + 输出流延迟 + 输出设备延迟

如果您想计算总往返延迟,则可以将以下内容相加:

输入延迟 + 输入安全偏移量。

您在渲染过程中看到的时间戳包括缓冲帧大小和安全偏移量,但流和设备延迟未被计算在内。

iOS 通过 AVAudioSession 提供了访问上述最重要信息的途径,正如提到的那样,您还可以使用"首选"会话设置- setPreferredIOBufferDurationpreferredIOBufferDuration 进行进一步控制。

/ The current hardware input latency in seconds. */
@property(readonly) NSTimeInterval inputLatency  NS_AVAILABLE_IOS(6_0);
/ The current hardware output latency in seconds. */
@property(readonly) NSTimeInterval outputLatency  NS_AVAILABLE_IOS(6_0);
/ The current hardware IO buffer duration in seconds. */
@property(readonly) NSTimeInterval IOBufferDuration  NS_AVAILABLE_IOS(6_0);

音频单元还具有可以查询的属性。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接