我在AVAudioPlayerNode中使用多个AVAudioEngine来混合音频文件以进行播放。
一旦完成所有设置(准备好引擎,启动引擎,安排音频文件片段),我将在每个播放器节点上调用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
}

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

明显的延迟大约是100ms,这是非常大的,我需要精确的当前时间值才能并行进行视觉渲染。

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

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

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

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

最佳答案

摘自theanalogkid在Apple开发人员论坛上的帖子:
在系统上,延迟的测量方法是:
音频设备I/O缓冲区帧大小+输出安全偏移+输出流延迟+输出设备延迟
如果您要计算总往返延迟,则可以添加:
输入延迟+输入安全偏移与上述相同。
您在渲染过程中看到的时间戳。会考虑缓冲区帧大小和安全偏移,但不会考虑流和设备延迟。
iOS使您可以通过AVAudioSession访问上述最重要的信息,并且如上所述,您还可以使用“首选” session 设置- 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);
音频单元还具有您可以查询的kAudioUnitProperty_Latency属性。

关于ios - AVAudioPlayerNode lastRenderTime,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42386497/

10-13 03:43