我一直在寻找这个问题的答案大约一个月了,所以对任何帮助表示赞赏!
我正在使用AVAudioEngine来录制音频。使用水龙头录制此音频:
localInput?.installTap(onBus: 0, bufferSize: 4096, format: localInputFormat) {
记录为AVAudioPCMBuffer类型。它需要转换为[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
}
然后将音频写入输出流。在另一台设备上,数据需要转换回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
}
然而,我的逻辑肯定有问题,因为在设备上,当我播放音频时,我确实听到了一些声音,但它听起来像是静态的。
正如我所说,任何帮助都表示赞赏,我已经暂时停留在这个问题上了一段时间。
感谢您的帮助。我已切换到使用数据。所以我的转换看起来像这样(我在网上找到了这个代码):
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
}
不幸的是,同样的问题仍然存在......
我已经创建了一个模拟此问题的项目。它所做的就是录制音频,将其转换为数据,将其转换回AVAudioPCMBuffer,然后播放音频。
这是链接: https://github.com/Lkember/IntercomTest
使用带有2个频道的设备时发生了崩溃,但我已修复它。
提交的答案修复了我的示例项目中的问题,但它没有解决我的主项目中的问题。我在这里添加了一个新问题:
答案 0 :(得分:1)
免责声明:好的,这完全基于苹果文档中的理论 - 我以前没有这样做,你的代码也没有足够的信息,以便理解你想要完成的整个事情。
首先,您要尝试将.floatChannelData
转换为Uint8
,根据文档集
通过将给定的浮点值舍入为零来创建新实例。
这会导致数组填充可能错误或更糟,空值(空,如零)。
据我了解,.withMemoryRebound
将 NOT 允许您将浮点数作为整数访问。隐式转换将削减数字,因此应该扭曲您的结果。这不是你想要的。
相反,您应该使用Audio Converter Services (documentation)
将您的浮点audioBuffer 安全和无损转换为整数audioBuffer。
我认为这应该指向正确的方向。
在开始转换之前,您还应该检查AVAudioPCMBuffer
的格式。处理可能取决于案例。
我希望我能提供帮助。
答案 1 :(得分:0)
结帐https://www.iis.fraunhofer.de/en/ff/amm/dl/whitepapers.html 在这里使用信息我做了非常相似的事情。有一个详细的PDF和一些示例代码可以帮助您入门。
答案 2 :(得分:0)
你走了:
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
}