Преобразование потокового 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) вызывается каждый раз, когда я получаю аудиоданные из веб-сокета.

Мне интересно, неверен ли мой код для преобразования звука или есть лучшее решение этой проблемы, и я буду признателен за любой совет.

0 ответов

Другие вопросы по тегам