ios - AVAudioPlayerNode lastRenderTime

标签 ios avaudioengine avaudioplayernode

我使用多个 AVAudioPlayerNodeAVAudioEngine混合音频文件进行播放。
完成所有设置后(引擎准备好、启动、音频文件段已安排),我将调用 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
}

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

明显的延迟在 100ms 左右,非常大,我需要一个精确的当前时间值来并行进行视觉渲染。

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

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

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

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

最佳答案

来自 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/

相关文章:

ios - AForge FFT 给出的结果与 Accelerate FFT 不同

javascript - 如何避免 Angular 4 应用程序中的图像旋转

swift - 播放 AVAudioPCMBuffer 的片段

ios - 查看应用重启前后的日志

ios - 如何将 UILabel 标签重置为 Storyboard 中设置的内容

ios - 如何使用 AVAudioEngine 取消或删除回声/重复声音?

swift - 如何设置 AVAudioEngine 输入和输出设备 (swift/macos)

ios - 如何使用连接到 AVAudioEngine 混音器的节点同时播放缓冲区中的多个声音

SWIFT - 是否可以从 AVAudioEngine 或 AudioPlayerNode 保存音频?如果是,如何?

swift - AVAudioPCMBuffer 以编程方式构建,不以立体声播放