iOS17.3下GCDAsyncUdpSocket发送音频缓冲数据失败问题
iOS 17.3下GCDAsyncUdpSocket发送音频数据接收端无响应,iOS 15.3正常
在iOS 17.3设备上使用GCDAsyncUdpSocket发送音频缓冲数据时,接收端完全收不到数据;但相同代码在iOS 15.3设备上运行时,接收端能正常接收。尝试调整GCDAsyncUdpSocket的调用方式后仍无法解决问题,相关实现代码如下:
func setupAudio () { self.audioEngine = AVAudioEngine() self.audioPlayer = AVAudioPlayerNode() self.mixer = AVAudioMixerNode() self.audioEngine.attach(audioPlayer) self.mixer.volume = 0 self.audioEngine.attach(mixer) self.socket = GCDAsyncUdpSocket(delegate: self, delegateQueue: DispatchQueue.main) } func setupAudioEngine() { let audioEngine = AVAudioEngine() let inputNode = audioEngine.inputNode let inputFormat = inputNode.inputFormat(forBus: 0) let hardwareSampleRate = audioEngine.inputNode.inputFormat(forBus: 0).sampleRate print(audioEngine.inputNode.inputFormat(forBus: 0).settings) print(inputNode.inputFormat(forBus: 0).formatDescription) let outputFormat = AVAudioFormat(commonFormat: AVAudioCommonFormat.pcmFormatInt16, sampleRate: hardwareSampleRate, channels: 1, interleaved: false) let converter = AVAudioConverter(from: inputFormat, to: outputFormat!)! 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:"232.10.10.100" ?? "", onPort: 3434 ?? 0) try self.socket.beginReceiving() print("Socket started") } catch { print("Socket Started Error: \(error)") } } inputNode.installTap(onBus: 0, bufferSize: 1024, format: inputFormat) { (buffer: AVAudioPCMBuffer!, time: AVAudioTime!) -> Void in do { let inputBlock: AVAudioConverterInputBlock = { _, outStatus in outStatus.pointee = AVAudioConverterInputStatus.haveData return buffer } let frameCapacity = AVAudioFrameCount(outputFormat!.sampleRate) * buffer.frameLength / AVAudioFrameCount(buffer.format.sampleRate) let outputBuffer = AVAudioPCMBuffer( pcmFormat: outputFormat!, frameCapacity: frameCapacity )! var error: NSError? converter.convert(to: outputBuffer, error: &error, withInputFrom: inputBlock) let data = Data(buffer: UnsafeBufferPointer(start: outputBuffer.int16ChannelData![0], count: Int(outputBuffer.frameLength))) print(data) DispatchQueue.global(qos: .background).async { [weak self] in guard let self = self else { return } do { self.socket.send(data, withTimeout: 0, tag: 0) } catch { print("Socket send Error: \(error)") } } } catch { print(error) } } audioEngine.prepare() do { try audioEngine.start() print("Audio player started") } catch { print("Can't start the engine: \(error)") } }
排查方向与解决方案
1. 多播权限与网络配置问题
iOS 17对本地网络权限和多播(你使用的232.10.10.100是多播地址)限制更严格:
- 确保
Info.plist中添加NSLocalNetworkUsageDescription字段,填写本地网络权限的使用说明,iOS 14+必须配置才能访问本地网络设备和多播地址。 - 进入设备
设置-隐私与安全性-本地网络,确认你的App已获得权限。
2. 修正GCDAsyncUdpSocket的多播配置
当前使用的connect(toHost:)不适用于多播场景,需替换为多播专用逻辑:
// 替换原connect相关代码 try self.socket.joinMulticastGroup("232.10.10.100") try self.socket.bind(toPort: 3434) try self.socket.beginReceiving()
发送数据时直接指定多播地址,不要依赖connect后的默认发送目标:
self.socket.send(data, toHost: "232.10.10.100", port: 3434, withTimeout: 0, tag: 0)
3. 避免音频线程阻塞
iOS 17对音频线程的调度优先级要求更高,不要在音频Tap回调中直接做格式转换和Socket发送:
inputNode.installTap(onBus: 0, bufferSize: 1024, format: inputFormat) { buffer, time in // 拷贝音频缓冲到新对象,避免原缓冲被复用 let bufferCopy = AVAudioPCMBuffer(pcmFormat: buffer.format, frameCapacity: buffer.frameLength)! bufferCopy.frameLength = buffer.frameLength memcpy(bufferCopy.int16ChannelData![0], buffer.int16ChannelData![0], Int(buffer.frameLength) * 2) // 移到后台队列处理格式转换与发送 DispatchQueue.global(qos: .userInitiated).async { [weak self] in guard let self = self else { return } // 执行格式转换和Socket发送逻辑 // ... } }
4. 检查GCDAsyncUdpSocket版本
确保使用的GCDAsyncUdpSocket是最新版本,旧版本可能未适配iOS 17的网络API变化。
5. 验证数据包是否发出
用同一局域网内的Mac或其他设备抓包,确认iOS 17设备是否真的发送了UDP数据包;同时临时关闭VPN或代理,排除网络路由问题。
内容的提问来源于stack exchange,提问作者ridvan
相关产品推荐
相关产品推荐

