PCM转G711 μlaw原始格式遇缓冲无数据问题求助
问题分析与解决方案
你的核心误区在于对G711 uLaw格式的缓冲区访问方式错误,以及缓冲区长度设置的问题,具体修正如下:
1. 为什么floatChannelData是nil?
G711 uLaw是压缩音频格式,不属于PCM格式范畴。AVAudioPCMBuffer的floatChannelData仅对PCM格式(比如.pcmFormatFloat32)有效,对于压缩格式,这个属性必然是nil。你需要通过缓冲区的data属性来访问压缩后的uLaw字节数据。
2. 缓冲区长度设置错误
你直接把frameLength设为frameCapacity,但转换后的实际帧数可能和计算的容量不一致,应该让转换器自动设置实际的frameLength,不要手动赋值。
3. 修正后的代码示例
var audioEngine = AVAudioEngine() var convertFormatBasicDescription = AudioStreamBasicDescription( mSampleRate: 8000, mFormatID: kAudioFormatULaw, mFormatFlags: AudioFormatFlags(kAudioFormatULaw), mBytesPerPacket: 1, mFramesPerPacket: 1, mBytesPerFrame: 1, mChannelsPerFrame: 1, mBitsPerChannel: 8, mReserved: 0 ) func convert() { let inputNode = audioEngine.inputNode // 建议用输入节点的实际格式,避免强制指定不匹配的格式 guard let micInputFormat = inputNode.inputFormat(forBus: 0) else { print("无法获取麦克风输入格式") return } guard let convertFormat = AVAudioFormat(streamDescription: &convertFormatBasicDescription) else { print("创建转换格式失败") return } guard let converter = AVAudioConverter(from: micInputFormat, to: convertFormat) else { print("创建转换器失败") return } do { inputNode.installTap(onBus: 0, bufferSize: 1024, format: micInputFormat) { [weak self] (buffer, time) in var newBufferAvailable = true let inputCallback: AVAudioConverterInputBlock = { inNumPackets, outStatus in if newBufferAvailable { outStatus.pointee = .haveData newBufferAvailable = false return buffer } else { outStatus.pointee = .noDataNow return nil } } // 计算转换后的预期帧数 let expectedFrameCount = AVAudioFrameCount(convertFormat.sampleRate) * buffer.frameLength / AVAudioFrameCount(buffer.format.sampleRate) guard let convertedBuffer = AVAudioPCMBuffer(pcmFormat: convertFormat, frameCapacity: expectedFrameCount) else { print("创建转换缓冲区失败") return } var error: NSError? let status = converter.convert(to: convertedBuffer, error: &error, withInputFrom: inputCallback) // 检查转换状态 switch status { case .success: // 访问uLaw压缩数据:通过data属性获取字节 if let data = convertedBuffer.data { let byteCount = Int(convertedBuffer.frameLength) * Int(convertFormat.streamDescription.pointee.mBytesPerFrame) let uLawBytes = Data(bytes: data, count: byteCount) print("转换成功,uLaw数据长度:\(uLawBytes.count)") // 这里可以处理uLawBytes,比如发送或存储 } case .error: print("转换失败:\(error?.localizedDescription ?? "未知错误")") case .inputRanDry: print("输入数据不足") @unknown default: print("未知转换状态") } } audioEngine.prepare() try audioEngine.start() } catch { print("启动音频引擎失败:\(error.localizedDescription)") } }
额外注意事项
- 不要强制指定麦克风输入格式为
.pcmFormatFloat32+ 44100Hz,不同设备的麦克风默认格式可能不同,直接用inputNode.inputFormat(forBus: 0)获取实际格式更可靠。 - 转换后的uLaw数据是8bit单字节,每帧对应一个字节,所以
byteCount等于转换后的帧数。
内容的提问来源于stack exchange,提问作者zones
相关产品推荐
相关产品推荐

