如何转换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
的格式。 处理可能与案件有关。
我希望我能帮上忙。
查看https://www.iis.fraunhofer.de/en/ff/amm/dl/whitepapers.html使用这里的信息,我做了一些非常相似的事情。 有一个详细的PDF和一些示例代码,让你开始。