【问题标题】:Crash when repeating a sound with AudioEngine in Swift在 Swift 中使用 AudioEngine 重复声音时崩溃
【发布时间】:2015-10-30 19:33:14
【问题描述】:

我正在尝试播放具有不同效果的声音。在之前的 viewController 中,我录制了一个声音,然后在下一个屏幕中,可以播放效果。第一次它工作正常,但第二次它崩溃并出现如下错误:

2015-08-07 13:00:45.900 完美音高[9643:1121173] 13:00:45.900 错误:AVAudioEngine.mm:253:AttachNode:所需条件是 错误:!nodeimpl->HasEngineImpl() 2015-08-07 13:00:45.953 音高 完美[9643:1121173] 由于未捕获的异常而终止应用程序 'com.apple.coreaudio.avfaudio',原因:'所需条件为假: !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 类,但没有结果。

谢谢

【问题讨论】:

    标签: swift avaudioengine


    【解决方案1】:

    我知道这是一个老问题,但我没有看到上面的正确答案。

    它崩溃的原因实际上已在错误消息中概述:

    AttachNode:要求条件为假:!nodeimpl->HasEngineImpl()

    换句话说,在附加节点时,该节点必须尚未附加到引擎 (!nodeimpl->HasEngineImpl())。

    解决方案是在尝试再次添加之前使用audioEngine.detachNode 删除节点。

    【讨论】:

      【解决方案2】:

      最后崩溃是由于在viewDidLoad函数中初始化audioPlayerNode和audioEngine对象造成的。显然,每次使用它们时,或者可能在停止和重置之后,它们都需要实例化。 将这些行直接放在 playAudioWithVariablePitch 函数的开头而不是在 viewDidLoad 函数中,解决了崩溃问题。我仍然对音高、混响和回声的播放有问题。他们在到期之前就被削减了,我仍然不知道为什么。跟audioPlayerNode.scheduleFile方法的completionHandler有关。

      【讨论】:

        【解决方案3】:

        在我的例子中,我的计时器一次又一次地调用,这段代码是写在我的计时器里面的

        self.recognitionTask?.finish()
        node.removeTap(onBus: 0)
        self.request.endAudio()
        
        self.recognitionTask = nil
        //Maybe this line was causing the issue
        self.audioEngine.stop()
        

        因此,如果您已经停止了请求,移除了水龙头并停止了引擎,那么不应再次调用这些行。

        希望对大家有所帮助

        【讨论】:

          【解决方案4】:

          播放可变音高效果后,您似乎正在重置引擎。

          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 时,它​​会崩溃。

          【讨论】:

          • 注释完所有 autoEngine.reset() 行后它仍然崩溃。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-10-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多