I've tried tinkering with AVAudioEngine's start/reset flow, tried different category/mode combinations of my AVAudioSession (see my configureAudioSession method), and tried manually creating the tap format like so:let micFormat = mic.inputFormat(forBus: 0)var trueFormat: AVAudioFormat!if micFormat.sampleRate == 0 { trueFormat = AVAudioFormat(standardFormatWithSampleRate: 44100, channels: 1)} else { trueFormat = micFormat}print("installing tap: \(micFormat.sampleRate) -- \(micFormat.channelCount)")mic.installTap(onBus: 0, bufferSize: 2048, format: trueFormat) { (buffer, when) in print("in tap completion") let sampleData = UnsafeBufferPointer(start: buffer.floatChannelData![0], count: Int(buffer.frameLength))}这给了我一个类似但不同的错误:which gives me a similar, but different, error:[avae] AVAEInternal.h:70:_AVAE_Check: required condition is false: [AVAudioIONodeImpl.mm:896:SetOutputFormat: (IsFormatSampleRateAndChannelCountValid(hwFormat))]我看不到麦克风的格式数据根据是否播放过AVAudioPlayerNode而变化的任何原因.I can't see any reason why the microphone's format data would vary depending on whether or not an AVAudioPlayerNode has been played.推荐答案经过一番搜索,我发现了问题所在.问题出在音频引擎的 inputNode 单例中.从文档中:After some searching I've found the problem. The issue lies in the audio engine's inputNode singleton. From the docs: 首次访问inputNode时,音频引擎会按需创建单例.要接收输入,请从输入音频节点的输出连接另一个音频节点,或在其上创建录音水龙头. The audio engine creates a singleton on demand when inputNode is first accessed. To receive input, connect another audio node from the output of the input audio node, or create a recording tap on it.加上我遇到的格式问题的参考:Plus a reference to the format issue I was experiencing: 检查输入节点的输入格式(特别是硬件格式)是否为非零采样率和通道数,以查看是否启用了输入. Check the input format of input node (specifically, the hardware format) for a non-zero sample rate and channel count to see if input is enabled.在我的游乐场班级中,触发音频文件回放的流程在创建带有以下内容的活动链"之前从未访问引擎的 inputNode :In my playground class, the flow for triggering audio file playback never accesses the engine's inputNode before it creates an "active chain" with:audioEngine.connect(playerNode, to: audioEngine.outputNode, format: audioFile.processingFormat)如果您想让引擎在内部为输入配置自己,似乎必须在start()添加之前访问AVAudioEngine的 inputNode .即使stop()ing和reset()引擎也不会导致对 inputNode 的访问来重新配置引擎. (我怀疑通过 disconnectNode 调用手动断开活动链会允许内部重新配置,但我还不确定这一点.)It seems that you must access AVAudioEngine's inputNode before start()ing it if you want the engine to internally configure itself for input. Even stop()ing and reset()ing the engine does not cause an access of inputNode to reconfigure the engine. (I suspect the manually breaking the active chain via disconnectNode calls would allow for the internal reconfiguration but I don't yet know that for sure).因此,代码方面的修复很简单:实例化后立即访问引擎的输入节点,以便为音频输入配置引擎.这是整个课程,文件播放和麦克风点击可一起使用:So code-wise the fix was simple: simply access the engine's input node immediately after instantiation so that the engine is configured for audio input. Here's the entire class with both file playback and mic tapping working together:import UIKitclass AudioEnginePlaygroundViewController: UIViewController { private var audioEngine: AVAudioEngine! private var mic: AVAudioInputNode! private var micTapped = false override func viewDidLoad() { super.viewDidLoad() configureAudioSession() audioEngine = AVAudioEngine() mic = audioEngine.inputNode! } @IBAction func toggleMicTap(_ sender: Any) { if micTapped { mic.removeTap(onBus: 0) micTapped = false return } let micFormat = mic.inputFormat(forBus: 0) mic.installTap(onBus: 0, bufferSize: 2048, format: micFormat) { (buffer, when) in let sampleData = UnsafeBufferPointer(start: buffer.floatChannelData![0], count: Int(buffer.frameLength)) } micTapped = true startEngine() } @IBAction func playAudioFile(_ sender: Any) { stopAudioPlayback() let playerNode = AVAudioPlayerNode() let audioUrl = Bundle.main.url(forResource: "test_audio", withExtension: "wav")! let audioFile = readableAudioFileFrom(url: audioUrl) audioEngine.attach(playerNode) audioEngine.connect(playerNode, to: audioEngine.outputNode, format: audioFile.processingFormat) startEngine() playerNode.scheduleFile(audioFile, at: nil, completionHandler: nil) playerNode.play() } // MARK: Internal Methods private func configureAudioSession() { do { try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord, with: [.mixWithOthers, .defaultToSpeaker]) try AVAudioSession.sharedInstance().setActive(true) } catch { } } private func readableAudioFileFrom(url: URL) -> AVAudioFile { var audioFile: AVAudioFile! do { try audioFile = AVAudioFile(forReading: url) } catch { } return audioFile } private func startEngine() { guard !audioEngine.isRunning else { return } do { try audioEngine.start() } catch { } } private func stopAudioPlayback() { audioEngine.stop() audioEngine.reset() }} 这篇关于播放AVAudioPlayerNode时,AVAudioEngine inputNode的格式发生更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
09-11 06:30