AVAudioEngine中断后无法重启,报错561145187的解决咨询
解决AVAudioEngine中断后重启失败的问题
错误原因分析
错误码561145187对应AVAudioSessionErrorCannotStartPlaying,核心问题是你的中断处理流程存在资源清理不彻底、音频会话状态管理错误、引擎节点配置缺失的问题:
- 中断开始时未正确移除输入节点的Tap、未去激活音频会话
- 中断结束时重复创建引擎实例却未清理旧资源,会话激活时机错误,且缺少必要的节点连接逻辑
- 使用
try!隐藏了潜在错误,无法排查会话配置问题
修正后的中断处理实现
@objc func handleInterruption(notification: Notification) { guard let userInfo = notification.userInfo, let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt, let type = AVAudioSession.InterruptionType(rawValue: typeValue) else { return } switch type { case .began: print("interrupt begin") // 1. 停止Socket收发 socket.close() socket = nil // 2. 彻底清理音频引擎资源 audioEngine.inputNode.removeTap(onBus: 0) // 必须移除Tap,否则资源泄漏 audioEngine.stop() do { try AVAudioSession.sharedInstance().setActive(false, options: .notifyOthersOnDeactivation) } catch { print("Deactivate audio session failed: \(error)") } print("Audio engine stopped") case .ended: print("interrupt end") // 1. 重新初始化Socket socket = GCDAsyncUdpSocket(delegate: self, delegateQueue: DispatchQueue.main) DispatchQueue.global(qos: .background).async { [weak self] in guard let self = self else { return } do { self.socket.setIPv4Enabled(true) self.socket.setIPv6Enabled(false) try self.socket.connect(toHost: "239.10.10.100", onPort: 4545) try self.socket.beginReceiving() print("Socket started") } catch { print("Socket Started Error: \(error)") } } // 2. 重新配置音频会话 do { try AVAudioSession.sharedInstance().setCategory(.playAndRecord, mode: .voiceChat, options: [.allowBluetooth, .allowBluetoothA2DP]) try AVAudioSession.sharedInstance().setActive(true) print("Audio session activated") } catch { print("Audio session config failed: \(error)") return } // 3. 重置音频引擎(不需要重新创建实例,重置即可) audioEngine.reset() // 4. 重新配置输入节点 do { try audioEngine.inputNode.setVoiceProcessingEnabled(true) } catch { print("Enable voice processing failed: \(error)") return } // 5. 安装输入Tap(捕获错误,避免强制解包) let inputFormat = audioEngine.inputNode.inputFormat(forBus: 0) audioEngine.inputNode.installTap(onBus: 0, bufferSize: 1024, format: inputFormat) { [weak self] buffer, time in guard let self = self else { return } do { let inputBlock: AVAudioConverterInputBlock = { _, outStatus in outStatus.pointee = .haveData return buffer } let frameCapacity = AVAudioFrameCount(self.outputFormat.sampleRate) * buffer.frameLength / AVAudioFrameCount(buffer.format.sampleRate) guard let outputBuffer = AVAudioPCMBuffer(pcmFormat: self.outputFormat, frameCapacity: frameCapacity) else { print("Create output buffer failed") return } var error: NSError? self.converter.convert(to: outputBuffer, error: &error, withInputFrom: inputBlock) if let error = error { print("Convert audio format failed: \(error)") return } let data = Data(buffer: UnsafeBufferPointer(start: outputBuffer.int16ChannelData![0], count: Int(outputBuffer.frameLength))) DispatchQueue.global(qos: .background).async { [weak self] in guard let self = self else { return } do { try self.socket.send(data, withTimeout: 0, tag: 0) } catch { print("Socket send Error: \(error)") } } } catch { print("Tap processing error: \(error)") } } // 6. 启动引擎 audioEngine.prepare() do { try audioEngine.start() print("Audio engine started") } catch { print("Can't start the engine: \(error)") } default: print("Unknown interruption type") } }
关键修复点说明
- 中断开始时的资源清理:必须移除输入节点的Tap,否则旧Tap会占用音频资源导致重启失败;同时去激活音频会话,释放系统音频资源
- 避免重复创建引擎实例:使用
audioEngine.reset()重置引擎即可,无需重新创建,减少资源开销和潜在冲突 - 正确的会话激活时机:先配置会话类别,再激活会话,确保会话状态正确后再配置引擎
- 移除强制解包和
try!:替换为do-catch捕获错误,便于排查配置过程中的问题 - Socket初始化优化:将Socket的重新初始化放在音频会话配置之前,避免音频启动延迟
内容的提问来源于stack exchange,提问作者ridvan
相关产品推荐
相关产品推荐

