如何转换audio,以便可以跨设备进行stream式传输

编辑2:

我已经创build了一个模拟这个问题的项目。 它所做的只是录制audio,将其转换为数据,将其转换回AVAudioPCMBuffer并播放audio。

这里是链接: https : //github.com/Lkember/IntercomTest

使用具有2个通道的设备时出现故障,但是我已经修复了这个问题。


我一直在寻找这个问题的答案大约一个月,所以任何帮助表示赞赏!

我正在使用AVAudioEngine来录制audio。 这个audio是用一个水龙头logging的:

localInput?.installTap(onBus: 0, bufferSize: 4096, format: localInputFormat) { 

logging下来inputAVAudioPCMBuffer。 它需要转换为types[UInt8]

我这样做的方法:

 func audioBufferToBytes(audioBuffer: AVAudioPCMBuffer) -> [UInt8] { let srcLeft = audioBuffer.floatChannelData![0] let bytesPerFrame = audioBuffer.format.streamDescription.pointee.mBytesPerFrame let numBytes = Int(bytesPerFrame * audioBuffer.frameLength) // initialize bytes by 0 var audioByteArray = [UInt8](repeating: 0, count: numBytes) srcLeft.withMemoryRebound(to: UInt8.self, capacity: numBytes) { srcByteData in audioByteArray.withUnsafeMutableBufferPointer { $0.baseAddress!.initialize(from: srcByteData, count: numBytes) } } return audioByteArray } 

audio然后写入输出stream。 在另一台设备上,需要将数据转换回AVAudioPCMBuffer以便播放。 我用这个方法:

 func bytesToAudioBuffer(_ buf: [UInt8]) -> AVAudioPCMBuffer { let fmt = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 44100, channels: 1, interleaved: true) let frameLength = UInt32(buf.count) / fmt.streamDescription.pointee.mBytesPerFrame let audioBuffer = AVAudioPCMBuffer(pcmFormat: fmt, frameCapacity: frameLength) audioBuffer.frameLength = frameLength let dstLeft = audioBuffer.floatChannelData![0] buf.withUnsafeBufferPointer { let src = UnsafeRawPointer($0.baseAddress!).bindMemory(to: Float.self, capacity: Int(frameLength)) dstLeft.initialize(from: src, count: Int(frameLength)) } return audioBuffer } 

但是,我的逻辑肯定是有问题的,因为在设备上,当我播放audio时,我听到了一些东西,但是听起来像是静止的。

任何帮助表示赞赏,正如我所说,我一直在这个问题上停留了一段时间。


编辑:

感谢你目前的帮助。 我已经切换到使用数据。 所以我的转换看起来像这样(我发现这个代码在线):

 func audioBufferToData(audioBuffer: AVAudioPCMBuffer) -> Data { let channelCount = 1 let bufferLength = (audioBuffer.frameCapacity * audioBuffer.format.streamDescription.pointee.mBytesPerFrame) let channels = UnsafeBufferPointer(start: audioBuffer.floatChannelData, count: channelCount) let data = Data(bytes: channels[0], count: Int(bufferLength)) return data } 

转换回AVAudioPCMBuffer看起来像这样:

 func dataToAudioBuffer(data: Data) -> AVAudioPCMBuffer { let audioFormat = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 8000, channels: 1, interleaved: false) let audioBuffer = AVAudioPCMBuffer(pcmFormat: audioFormat, frameCapacity: UInt32(data.count)/2) audioBuffer.frameLength = audioBuffer.frameCapacity for i in 0..<data.count/2 { audioBuffer.floatChannelData?.pointee[i] = Float(Int16(data[i*2+1]) << 8 | Int16(data[i*2]))/Float(INT16_MAX) } return audioBuffer } 

不幸的是,同样的问题仍然存在…


编辑4:

提交的答案解决了我的示例项目中的问题,但是没有解决我的主项目中的问题。 我在这里添加了一个新的问题:

如何通过OutputStream发送NSData

干得好:

 func audioBufferToNSData(PCMBuffer: AVAudioPCMBuffer) -> NSData { let channelCount = 1 // given PCMBuffer channel count is 1 let channels = UnsafeBufferPointer(start: PCMBuffer.floatChannelData, count: channelCount) let data = NSData(bytes: channels[0], length:Int(PCMBuffer.frameCapacity * PCMBuffer.format.streamDescription.pointee.mBytesPerFrame)) return data } func dataToAudioBuffer(data: NSData) -> AVAudioPCMBuffer { let audioFormat = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 44100, channels: 1, interleaved: false) let audioBuffer = AVAudioPCMBuffer(pcmFormat: audioFormat, frameCapacity: UInt32(data.length) / audioFormat.streamDescription.pointee.mBytesPerFrame) audioBuffer.frameLength = audioBuffer.frameCapacity let channels = UnsafeBufferPointer(start: audioBuffer.floatChannelData, count: Int(audioBuffer.format.channelCount)) data.getBytes(UnsafeMutableRawPointer(channels[0]) , length: data.length) return audioBuffer } 

免责声明:好的,这是完全基于苹果文档的理论 – 我以前没有这样做过,你的代码也不够丰富,不能理解你要完成的所有事情。

首先,你正试图将.floatChannelData转换为.floatChannelData ,根据docsets

通过将给定的浮点值四舍五入来创build一个新的实例。

这将导致数组填充可能错误或更糟,空值(空,如在零)。

在我的理解, .withMemoryRebound 不会让你访问一个浮点数作为一个整数。 隐式转换减less数字,因此会扭曲你的结果。 这不是你想要的。

相反,你应该使用audio转换服务(文档)

把你的浮点数audio缓冲区安全无损转换成一个整数audio缓冲区。

我认为这应该指向正确的方向。 在开始转换之前,您还应该检查AVAudioPCMBuffer的格式。 处理可能与案件有关。

我希望我能帮上忙。