音频引擎仅在运行 iOS 10 的设备(iphone 6)上失败,在所有模拟器设备上运行良好或真实设备直到 iphone 6s

Posted

技术标签:

【中文标题】音频引擎仅在运行 iOS 10 的设备(iphone 6)上失败,在所有模拟器设备上运行良好或真实设备直到 iphone 6s【英文标题】:Audio engine fails only on device(iphone6s) running iOS10 , runs on All simulator devices well or real device til iphone 6s 【发布时间】:2016-09-21 10:37:21 【问题描述】:

我确实尝试将效果添加到音频文件,它确实适用于 ios 9,但在 iOS10 中它仅在 iphone 6s 中失败,在旧设备上运行,在模拟器中运行良好,我的信息中确实有隐私使用说明。用于照片、相机和 microfon 的 plist 文件 我确实在 audioEngine.mainMixerNode.installTapOnBus 线上得到了输卵管错误

2016-09-21 13:08:20.109701 $$$$[557:86076] [central] 54:   ERROR:    [0x16e34f000] >avae> AVAudioNode.mm:751: AUSetFormat: error -10865 
2016-09-21 13:08:20.110111 Tell Your Story[557:86076] *** Terminating app due to uncaught exception 'com.apple.coreaudio.avfaudio', reason: 'error -10865'

我用于添加音频效果的函数

   private fund addEffetToAudioFile(pitch: Float, rate: Float, reverb: Float, echo: Float)  // Initialize variables
    audioEngine = AVAudioEngine()
    audioPlayerNode = AVAudioPlayerNode()
    audioEngine.attachNode(audioPlayerNode)

    // Setting the pitch
    let pitchEffect = AVAudioUnitTimePitch()
    pitchEffect.pitch = pitch
    audioEngine.attachNode(pitchEffect)

    // Setting the platback-rate
    let playbackRateEffect = AVAudioUnitVarispeed()
    playbackRateEffect.rate = rate
    audioEngine.attachNode(playbackRateEffect)

    // Setting the reverb effect
    let reverbEffect = AVAudioUnitReverb()
    reverbEffect.loadFactoryPreset(AVAudioUnitReverbPreset.Cathedral)
    reverbEffect.wetDryMix = reverb
    audioEngine.attachNode(reverbEffect)

    // Setting the echo effect on a specific interval
    let echoEffect = AVAudioUnitDelay()
    echoEffect.delayTime = NSTimeInterval(echo)
    audioEngine.attachNode(echoEffect)

    // Chain all these up, ending with the output
    audioEngine.connect(audioPlayerNode, to: playbackRateEffect, format: nil)
    audioEngine.connect(playbackRateEffect, to: pitchEffect, format: nil)
    audioEngine.connect(pitchEffect, to: reverbEffect, format: nil)
    audioEngine.connect(reverbEffect, to: echoEffect, format: nil)
    audioEngine.connect(echoEffect, to: audioEngine.mainMixerNode, format: nil)

    // Good practice to stop before starting
    audioPlayerNode.stop()

    // Play the audio file
    if (audioEngine != nil) 
        audioEngine?.stop()
    

    do 
        audioFile = try AVAudioFile(forReading: self.recordedAudioURL)
     catch 
        print("Error: Can't create audio file")
        self.showAlert(TYSAudioEditorHelper.Alerts.AudioFileError, message: String(error))
        return
    

    audioPlayerNode.scheduleFile(audioFile, atTime: nil, completionHandler: 
        print("Complete")
    )

    try! audioEngine.start()

    let dirPaths: AnyObject = NSSearchPathForDirectoriesInDomains( NSSearchPathDirectory.DocumentDirectory,  NSSearchPathDomainMask.UserDomainMask, true)[0]
    let tmpFileUrl: NSURL = NSURL.fileURLWithPath(dirPaths.stringByAppendingPathComponent(kOutputSoundWithEffectFileName))
    do 
        self.newAudio = try AVAudioFile(forWriting: tmpFileUrl, settings:[
            AVFormatIDKey: NSNumber(unsignedInt:kAudioFormatMPEG4AAC_HE),
            AVEncoderAudioQualityKey : AVAudioQuality.Medium.rawValue,
            AVEncoderBitRateKey : 12800,
            AVNumberOfChannelsKey: 2,
            AVSampleRateKey : 44100.0
            ])

     /*Error in this line*/   audioEngine.mainMixerNode.installTapOnBus(0, bufferSize: 2048, format: audioEngine.mainMixerNode.inputFormatForBus(1))  (buffer: AVAudioPCMBuffer!, time: AVAudioTime!) -> Void  in
            print(self.newAudio.length)
            if (self.newAudio.length) < (self.audioFile.length) 
                //Let us know when to stop saving the file, otherwise saving infinitely
                do 
                    try self.newAudio.writeFromBuffer(buffer)
                 catch 
                    print("Problem Writing Buffer")
                
             else 
                self.audioEngine.mainMixerNode.removeTapOnBus(0)
                //if we dont remove it, will keep on tapping infinitely
                self.newAudio = nil
                if (self.audioEngine != nil) 
                    self.audioEngine?.stop()
                
                self.removeOldFileIfExist(self.kOriginalVideoSoundFileName)
                self.saveAudioFileInVideo(tmpFileUrl)
            
        
     catch 
        print("Problem")
    

    do 
        try audioEngine.start()
     catch 
        showAlert(TYSAudioEditorHelper.Alerts.AudioEngineError, message: String(error))
        return
    

    // play the recording!
    audioPlayerNode.play()

【问题讨论】:

【参考方案1】:

根据https://developer.apple.com/reference/audiotoolbox/1584138-anonymous/kaudiouniterr_propertynotwritable?language=objc那个错误是

kAudioUnitErr_PropertyNotWritable = -10865

根据https://developer.apple.com/reference/avfoundation/avaudionode/1387122-installtap

格式: 如果非零,则尝试将其应用为指定输出总线的格式。 仅当连接到未连接到另一个节点的输出总线时才应该这样做;否则将导致错误。指定总线上的抽头和连接格式(如果非零)应该相同。否则,后一个操作将覆盖任何先前设置的格式。 对于 AVAudioOutputNode,tap 格式必须指定为 nil。

所以可能是以下之一:

    mainMixerNode已经连接到另一个节点,所以在安装tap之前需要断开它们

    mainMixerNode是一个AVAudioOutputNode,所以这个参数需要传入nil

【讨论】:

发现问题只需要评论这一行 -> //try! audioEngine.start() @ivan123 直接评论 audioengine.start 函数会给你错误,因为它是应该启动 audioengine 的情况。你解决了这个问题吗?

以上是关于音频引擎仅在运行 iOS 10 的设备(iphone 6)上失败,在所有模拟器设备上运行良好或真实设备直到 iphone 6s的主要内容,如果未能解决你的问题,请参考以下文章

在运行 ios 13 的设备上没有应用程序崩溃的情况下无法播放音频文件

iPhone:AVAudioPlayer 并不总是在设备上播放音频

仅在 ios 设备上反应本机“不存在捆绑 URL”

MPVolumeView 未在 iOS 11 上显示音频路由

iOS4 - iPhone 模拟器的背景音频

应用程序仅在 iOS 6 中旋转,在 iOS 5 中不旋转