我在 iOS 游戏应用程序中使用 AVAudioEngine 音频。我遇到的一个问题是 AVAudioPlayerNode.play() 需要很长时间才能执行,这在游戏等实时应用程序中可能是一个问题。
play() 只是激活播放器节点 - 您不必每次播放声音时都调用它。因此,不必经常调用它,但必须偶尔调用它,例如最初激活播放器,或在它被停用后(在某些情况下会发生)。即使只是偶尔调用,较长的执行时间也可能是个问题,尤其是当您需要同时在多个播放器上调用 play() 时。
play() 的执行时间似乎与 AVAudioSession.ioBufferDuration 的值成正比,您可以使用 AVAudioSession.setPreferredIOBufferDuration() 请求更改该值。这是我用来测试的一些代码:
import AVFoundation
import UIKit
class ViewController: UIViewController {
private let engine = AVAudioEngine()
private let player = AVAudioPlayerNode()
private let ioBufferSize = 1024.0 // Or 256.0
override func viewDidLoad() {
super.viewDidLoad()
let audioSession = AVAudioSession.sharedInstance()
try! audioSession.setPreferredIOBufferDuration(ioBufferSize / 44100.0)
try! audioSession.setActive(true)
engine.attach(player)
engine.connect(player, to: engine.mainMixerNode, format: nil)
try! engine.start()
print("IO buffer duration: \(audioSession.ioBufferDuration)")
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if player.isPlaying {
player.stop()
} else {
let startTime = CACurrentMediaTime()
player.play()
let endTime = CACurrentMediaTime()
print("\(endTime - startTime)")
}
}
}
以下是我使用 1024 缓冲区大小(我相信这是默认值)获得的 play() 的一些示例计时:
0.0218
0.0147
0.0211
0.0160
0.0184
0.0194
0.0129
0.0160
以下是使用 256 缓冲区大小的一些示例时序:
0.0014
0.0029
0.0033
0.0023
0.0030
0.0039
0.0031
0.0032
正如您在上面看到的,对于 1024 的缓冲区大小,执行时间往往在 15-20 毫秒范围内(大约 60 FPS 的全帧)。缓冲区大小为 256 时,大约为 3 毫秒 - 没有那么糟糕,但当您每帧只有约 17 毫秒可以使用时仍然很昂贵。
这是在运行 iOS 12.4.2 的 iPad Mini 2 上。这显然是一个旧设备,但我在模拟器上看到的结果似乎是成比例的,所以它似乎更多地与缓冲区大小和函数本身的行为有关,而不是与所使用的硬件有关。我不知道幕后发生了什么,但似乎 play() 阻塞直到下一个音频周期的开始,或类似的东西。
请求较小的缓冲区大小似乎是部分解决方案,但也有一些潜在的缺点。根据此处的文档,从文件流式传输时,较低的缓冲区大小可能意味着更多的磁盘访问,不管怎样,请求可能根本不会被兑现。另外,在这里,有人报告了与低缓冲区大小相关的播放问题。考虑到所有这些,我不愿意将其作为解决方案。
这使我的 play() 执行时间在 15-20 毫秒范围内,这通常意味着 60 FPS 的帧丢失。如果我安排事情,以便一次只调用一次 play() 并且不频繁,也许它不会被注意到,但这并不理想。
我已经搜索了信息并在其他地方询问过这个问题,但似乎没有多少人在实践中遇到这种行为,或者这对他们来说不是问题。
AVAudioEngine 旨在用于实时应用程序,所以如果我是正确的 AVAudioPlayerNode.play() 阻塞了与缓冲区大小成比例的大量时间,这似乎是一个设计问题。我意识到这可能不是许多人正在处理的问题,但我在这里发帖询问是否有人遇到过 AVAudioEngine 的这个特定问题,如果是,是否有任何见解、建议或解决方法,任何人都可以提供。