我试图播放具有不同效果的声音。在之前的viewController中我录制了一个声音,然后在下一个屏幕中,它可以用效果播放。第一次它工作正常但第二次崩溃时出现如下错误:
2015-08-07 13:00:45.900 Pitch Perfect [9643:1121173] 13:00:45.900 错误:AVAudioEngine.mm:253:AttachNode:必需条件是 false:!nodeimpl-> HasEngineImpl()2015-08-07 13:00:45.953 Pitch 完美[9643:1121173]由于未捕获的异常而终止应用程序 ' com.apple.coreaudio.avfaudio',原因:'必需条件为false: !nodeimpl-> HasEngineImpl()'
import UIKit
import AVFoundation
class PlaySoundsViewController: UIViewController, AVAudioPlayerDelegate {
var receivedAudio:RecordedAudio!
var audioPlayer: AVAudioPlayer!
var disabledButton:UIButton!
var firstTime:Bool = true
var audioEngine:AVAudioEngine!
var audioFile:AVAudioFile!
var audioPlayerNode:AVAudioPlayerNode!
var audioStopped:Bool!
var typeOfSound:IntegerLiteralType!
@IBOutlet weak var stopButton: UIButton!
@IBOutlet weak var reverbButton: UIButton!
@IBOutlet weak var echoButton: UIButton!
@IBOutlet weak var darthButton: UIButton!
@IBOutlet weak var chipmonkButton: UIButton!
@IBOutlet weak var snailButton: UIButton!
@IBOutlet weak var rabbitButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
audioPlayer = AVAudioPlayer(contentsOfURL: receivedAudio.filePathUrl, error: nil)
audioPlayer.enableRate=true
audioPlayer.delegate=self
var session = AVAudioSession.sharedInstance()
session.setCategory(AVAudioSessionCategoryPlayback, error: nil)
audioPlayerNode=AVAudioPlayerNode();
audioEngine = AVAudioEngine()
audioFile = AVAudioFile(forReading: receivedAudio.filePathUrl, error: nil)
audioStopped=true;
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func playAnimalSound(animal: String) {
if audioStopped==false {
resetAudio(typeOfSound)
}
typeOfSound = 1
audioPlayer.currentTime=0
switch animal {
case "snail":
audioPlayer.rate=0.5
case "rabbit":
audioPlayer.rate=2.0
default:
showMessage("Sound not found. How can it be?")
}
audioPlayer.play()
stopButton.hidden=false
stopButton.enabled=true
}
@IBAction func playSnailSound(sender: UIButton) {
highlightButton(sender)
playAnimalSound("snail")
}
@IBAction func playRabbitSound(sender: UIButton) {
highlightButton(sender)
playAnimalSound("rabbit")
}
func soundEnded() {
stopButton.hidden=true
disabledButton.enabled=true;
if(audioEngine.running) {
audioEngine.stop()
audioEngine.reset();
}
}
func playAudioWithVariablePitch(pitch: Float, type: String) {
if audioStopped==false {
resetAudio(typeOfSound)
}
audioEngine.attachNode(audioPlayerNode)
switch type {
case "normal":
typeOfSound = 2
var changePitchEffect = AVAudioUnitTimePitch()
changePitchEffect.pitch = pitch
audioEngine.attachNode(changePitchEffect)
audioEngine.connect(audioPlayerNode, to: changePitchEffect, format: nil)
audioEngine.connect(changePitchEffect, to: audioEngine.outputNode, format: nil)
case "reverb":
typeOfSound = 3
var changeReverbEffect = AVAudioUnitReverb()
changeReverbEffect.loadFactoryPreset(AVAudioUnitReverbPreset(rawValue: 4)!)
changeReverbEffect.wetDryMix=50;
audioEngine.attachNode(changeReverbEffect)
audioEngine.connect(audioPlayerNode, to: changeReverbEffect, format: nil)
audioEngine.connect(changeReverbEffect, to: audioEngine.outputNode, format: nil)
case "delay":
typeOfSound = 3
var changeDelayEffect = AVAudioUnitDelay()
audioEngine.attachNode(changeDelayEffect)
audioEngine.connect(audioPlayerNode, to: changeDelayEffect, format: nil)
audioEngine.connect(changeDelayEffect, to: audioEngine.outputNode, format: nil)
default:
showMessage("oops, there was an internal problem. Never mind")
}
audioPlayerNode.scheduleFile(audioFile, atTime: nil, completionHandler: soundEnded)
audioEngine.startAndReturnError(nil)
stopButton.hidden=false
stopButton.enabled=true
audioPlayerNode.play()
}
func audioPlayerDidFinishPlaying(player: AVAudioPlayer!, successfully flag: Bool) {
if flag {
stopButton.hidden=true
disabledButton.enabled=true;
audioStopped=true
println("I hid stopButton and enabled the disabled one")
}
}
@IBAction func playDelaySound(sender: UIButton) {
highlightButton(sender)
playAudioWithVariablePitch(0, type: "delay")
}
@IBAction func playReverbSound(sender: UIButton) {
highlightButton(sender)
playAudioWithVariablePitch(0, type: "reverb")
}
@IBAction func playChipmunkSound(sender: UIButton) {
highlightButton(sender)
playAudioWithVariablePitch(1000.0, type: "normal")
}
@IBAction func playDarthVaderSound(sender: UIButton) {
highlightButton(sender)
playAudioWithVariablePitch(-900.0, type: "normal")
}
@IBAction func stopPlaying(sender: UIButton) {
resetAudio(typeOfSound)
stopButton.hidden=true
stopButton.enabled=false;
disabledButton.enabled=true;
}
func highlightButton(button: UIButton) {
if firstTime {
firstTime=false
} else {
disabledButton.enabled=true;
}
button.enabled=false;
disabledButton=button;
}
func resetAudio(type: IntegerLiteralType) {
switch type {
case 1 :
audioPlayer.stop()
println("case 1")
case 2 :
println("case 2")
if audioEngine.running {
audioEngine.stop()
}
audioEngine.reset()
case 3 :
audioEngine.stop()
default:
break
}
audioStopped=true;
}
func showMessage(msg: String) {
var message=UIAlertView(title: "Alert", message: msg, delegate: nil, cancelButtonTitle: "ok I won't panic")
}
}
有人知道它崩溃的原因吗?我研究过没有结果的AVAudioEngine,AVAudioPlayer和AVAudioPlayerNode类。
由于
答案 0 :(得分:9)
我知道这是一个老问题,但我没有看到上面的正确答案。
崩溃的原因实际上在错误消息中列出:
AttachNode:必需条件为false:!nodeimpl-> HasEngineImpl()
换句话说,在附加节点时,必须将该节点连接到引擎(!nodeimpl->HasEngineImpl()
)。
解决方案是在尝试再次添加节点之前使用audioEngine.detachNode
删除节点。
答案 1 :(得分:3)
最后,崩溃是由viewDidLoad函数中的audioPlayerNode和audioEngine对象初始化引起的。它们需要在每次使用它们时进行实例化,显然,或者可能在被停止和重置之后。 直接将这些行放在playAudioWithVariablePitch函数的开头,而不是在viewDidLoad函数中,解决了崩溃问题。我仍然有播放音调,混响和回声的问题。它们会在它到期前被切断,我仍然不知道为什么。它与audioPlayerNode.scheduleFile方法的completionHandler有关。
答案 2 :(得分:0)
看起来你在播放可变音高效果后重置引擎。
func soundEnded() {
stopButton.hidden=true
disabledButton.enabled=true;
if(audioEngine.running) {
audioEngine.stop()
audioEngine.reset();
}
}
audioPlayerNode.scheduleFile(audioFile, atTime: nil, completionHandler: soundEnded)
audioEngine.startAndReturnError(nil)
stopButton.hidden=false
stopButton.enabled=true
audioPlayerNode.play()
因此,添加节点并链接链接后,引擎尚未重新设置。当你尝试播放playerNode时,它会崩溃。
答案 3 :(得分:0)
在我的情况下,我的计时器一次又一次地调用,并且这段代码被写入了我的计时器
self.recognitionTask?.finish()
node.removeTap(onBus: 0)
self.request.endAudio()
self.recognitionTask = nil
//Maybe this line was causing the issue
self.audioEngine.stop()
因此,如果您已经停止了该请求,卸下了水龙头并停止了引擎,那么这些行将不再被调用。
希望这对某些人有帮助