0

我有一个语音流应用程序,它通过 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 接收音频数据时都会调用它。

我想知道我用于转换音频的代码是否不正确,或者是否有更好的解决方案来解决这个问题,并希望得到任何建议。

4

0 回答 0