我有一个语音流应用程序,它通过 websocket 接收实时音频,编码为 G.711 u-law 8KHz 单声道,我想使用AVAudioEngine
.
为此,我将音频样本转换为具有相同采样率和音频参数的 PCM (Float32),使用AVAudioConverter
.
出于某种原因,我听到的声音是金属的和回声的。
这是我的代码:
class AudioEngine {
private var engine: AVAudioEngine!
// Audio player
private var playerNode: AVAudioPlayerNode!
private let playerFormat = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 8000, channels: 1, interleaved: false)
// AudioConverter properties
private var inputConverter: AVAudioConverter? // audioIn (Player)
private lazy var inputDescriptor = AudioStreamBasicDescription(mSampleRate: 8000, mFormatID: kAudioFormatULaw, mFormatFlags: 0, mBytesPerPacket: 1, mFramesPerPacket: 1, mBytesPerFrame: 1, mChannelsPerFrame: 1, mBitsPerChannel: 8, mReserved: 0)
private var inputFormat: AVAudioFormat?
init() {
engine = AVAudioEngine()
setupPlayerFormats()
setupSession()
setupPlayer()
}
deinit {
stopStream()
}
func playStream() throws {
guard !engine.isRunning else {
print("engine is running")
return
}
try engine.start()
playerNode.play()
print("playing stream")
}
func stopStream() {
playerNode.stop()
engine.stop()
}
/// each byte of kAudioFormatULaw is converted to 4 bytes of pcmFormatFloat32
func convertAudio(data: Data) {
guard let sourceFormat = inputFormat,
let targetFormat = playerFormat,
let dataBuffer = data.makePCMBuffer(format: sourceFormat),
let pcmBuffer = AVAudioPCMBuffer(pcmFormat: targetFormat, frameCapacity: dataBuffer.frameLength) else {
fatalError("Unable to set audio player converter formats")
}
do {
try inputConverter?.convert(to: pcmBuffer, from: dataBuffer)
} catch let error as NSError {
print("audioIn (Player) Conversion error=\(error)")
}
let audioBufferSize = pcmBuffer.audioBufferList.pointee.mBuffers.mDataByteSize
if audioBufferSize > 0 {
self.playerNode.scheduleBuffer(pcmBuffer, completionHandler: nil)
}
}
private extension AudioEngine {
func setupPlayerFormats() {
inputFormat = AVAudioFormat(streamDescription: &inputDescriptor)
guard let source = inputFormat, let output = playerFormat else {
fatalError("Unable to set audio player formats")
}
inputConverter = AVAudioConverter(from: source, to: output)
}
func setupSession() {
let session = AVAudioSession.sharedInstance()
do {
try session.setCategory(.playAndRecord, mode: .voiceChat)
try session.setActive(true, options: .notifyOthersOnDeactivation)
} catch let error as NSError {
fatalError("Unable to setup audio session with error=\(error)")
}
}
func setupPlayer() {
playerNode = AVAudioPlayerNode()
engine.attach(playerNode)
engine.connect(playerNode, to: engine.mainMixerNode, format: playerFormat)
}
}
func convertAudio(data: Data)
每次我从 websocket 接收音频数据时都会调用它。
我想知道我用于转换音频的代码是否不正确,或者是否有更好的解决方案来解决这个问题,并希望得到任何建议。