将流式 u-law 转换为 PCM 听起来很金属

如何解决将流式 u-law 转换为 PCM 听起来很金属

我有一个语音流应用,它通过网络套接字接收实时音频,编码为 G.711 u-law 8KHz 单声道,我想使用 AVAudioEngine 播放。

为此,我使用 AVAudioConverter 将音频样本转换为具有相同采样率和音频参数的 PCM (Float32)。

出于某种原因,我听到的声音是金属和回声。

这是我的代码

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)
    }
}

每次我从 websocket 接收音频数据时都会调用

func convertAudio(data: Data)

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?