我是iOS的初学者,我正在尝试用Swift设计一个鼓集应用程序。我用一个按钮设计了一个视图,并编写了下面的代码,但是它有一些问题:
AVAudioPlayer不是低延迟音频的最佳选择,但作为初学者,如果没有Swift的代码示例或教程,很难学习OpenAL、AudioUnit。问题与此类似:在低延迟的iOS中,我应该使用哪个框架来播放音频文件(WAV、MP3、AIFF)?。守则:
override func viewDidLoad() {
super.viewDidLoad()
// Enable multiple touch for the button
for v in view.subviews {
if v.isKindOfClass(UIButton) {
v.multipleTouchEnabled = true
}
}
// Init audio
audioURL = NSBundle.mainBundle().URLForResource("snareDrum", withExtension: "wav")!
do {
player = try AVAudioPlayer(contentsOfURL: audioURL)
player?.prepareToPlay()
} catch {
print("AVAudioPlayer Error")
}
}
override func viewDidDisappear(animated: Bool) {
super.viewDidDisappear(animated)
player?.stop()
player = nil
}
@IBAction func playSound(sender: UIButton) {
player?.currentTime = 0
player?.play()
}发布于 2016-02-06 18:53:11
如果您需要极低的延迟时间,我在AVAudioSession单例上发现了一个非常简单的解决方案(在应用程序启动时会自动实例化):
首先,使用以下类方法获取对应用程序的AVAudioSession单例的引用:
(来自AVAudioSession类引用):
获取共享音频会话 声明SWIFT
class func sharedInstance() -> AVAudioSession
然后,尝试使用此实例方法将首选IO缓冲区持续时间设置为非常短的(例如.002):
设置首选音频I/O缓冲区持续时间(以秒为单位)。 声明SWIFT
func setPreferredIOBufferDuration(_ duration: NSTimeInterval) throws参数duration要使用的音频I/O缓冲区持续时间(以秒为单位)。outError在输入时,指向错误对象的指针。如果发生错误,则将指针设置为描述错误的NSError对象。如果不需要错误信息,请输入零。如果请求成功,则返回值true,否则返回false。 讨论 此方法请求更改I/O缓冲区持续时间。若要确定更改是否生效,请使用IOBufferDuration属性。有关详细信息,请参阅配置音频会话。
请记住上面的注意事项-- IOBufferDuration属性是否实际上设置为传递给func setPrefferedIOBufferDuration(_ duration: NSTimeInterval) throws方法的值,取决于函数不返回错误、和其他我不完全清楚的因素。而且--在我的测试中--我发现如果将这个值设置为极低的值,值(或接近它的值)确实会被设置,但是当播放一个文件(例如使用AVAudioPlayerNode)时,声音将不会被播放。没有错误,只是没有声音。这显然是个问题。我还没有发现如何测试这个问题,除非我注意到在实际设备上测试时耳朵里没有声音。我将会调查此事。但就目前而言,我建议将首选持续时间设置为不少于.002或.0015。.0015的价值似乎适用于我正在测试的iPad Air (型号A1474)。虽然.0012很低,但在我的iPhone 6S上工作得很好。
从CPU开销的角度考虑的另一件事是音频文件的格式。未压缩格式在播放时具有非常低的CPU开销。Apple建议,为了获得最高的质量和最低的开销,您应该使用CAF文件。对于压缩文件和最低开销,您应该使用IMA4压缩:
(来自iOS多媒体编程指南):
首选的音频格式在iOS为未压缩(最高质量)音频,使用16位,小终端,线性PCM音频数据打包在一个CAF文件。您可以使用af红外命令行工具在Mac中将音频文件转换为此格式,如下所示:
/usr/bin/afconvert -f caff -d LEI16 {INPUT} {OUTPUT}
当您需要同时播放多个声音时,若要减少内存使用量,请使用IMA4 (IMA/ADPCM)压缩。这减少了文件大小,但在解压缩过程中对CPU的影响最小。与线性PCM数据一样,将IMA4数据打包到CAF文件中。
您也可以使用afconvert转换为IMA4:
/usr/bin/afconvert -f AIFC -d ima4 [file]
发布于 2017-12-08 20:57:05
我花了一个下午的时间试图通过玩AVAudioPlayer & AVAudioSession来解决这个问题,但是我没有办法解决这个问题。(不幸的是,按照这里接受的答案所建议的设置IO缓冲区持续时间似乎没有帮助。)我也尝试过AudioToolbox,但是我发现结果的性能几乎是一样的--在相关的用户操作和音频之间显然是一个明显的延迟。
在浏览了一下互联网之后,我发现:
www.rockhoppertech.com/blog/swift-avfoundation/
关于AVAudioEngine的部分被证明是非常有用的。下面的代码是稍加修改的:
import UIKit
import AVFoundation
class ViewController: UIViewController {
var engine = AVAudioEngine()
var playerNode = AVAudioPlayerNode()
var mixerNode: AVAudioMixerNode?
var audioFile: AVAudioFile?
@IBOutlet var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
engine.attach(playerNode)
mixerNode = engine.mainMixerNode
engine.connect(playerNode, to: mixerNode!, format: mixerNode!.outputFormat(forBus: 0))
do {
try engine.start()
}
catch let error {
print("Error starting engine: \(error.localizedDescription)")
}
let url = Bundle.main.url(forResource: "click_04", withExtension: ".wav")
do {
try audioFile = AVAudioFile(forReading: url!)
}
catch let error {
print("Error opening audio file: \(error.localizedDescription)")
}
}
@IBAction func playSound(_ sender: Any) {
engine.connect(playerNode, to: engine.mainMixerNode, format: audioFile?.processingFormat)
playerNode.scheduleFile(audioFile!, at: nil, completionHandler: nil)
if engine.isRunning{
playerNode.play()
} else {
print ("engine not running")
}
}}
这可能不是完美的,因为我是一个斯威夫特新手,以前没有使用过AVAudioEngine。不过,它似乎确实有效!
https://stackoverflow.com/questions/34680007
复制相似问题