Преобразование потокового U-закона в PCM звучит металлически
У меня есть приложение для потоковой передачи голоса, которое принимает живой звук через веб-сокет, закодированный как моно G.711 u-law 8 кГц, которое я хочу воспроизвести, используя
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)
вызывается каждый раз, когда я получаю аудиоданные из веб-сокета.
Мне интересно, неверен ли мой код для преобразования звука или есть лучшее решение этой проблемы, и я буду признателен за любой совет.