带有 AVAudioConverterInputBlock 的 AVAudioConverter 在处理后会出现音频断断续续的情况

2023-11-24

我正在尝试将音频缓冲区转换为不同的格式,并且我正在使用 AVAudioConverter。当您具有相同的采样率并且不需要使用 AVAudioConverterInputBlock 时,AVAudioConverter 会完成这项工作。

但如果我处理相同的采样率,我的音频数据就会出现奇怪的口吃现象。我有一种感觉,我没有很好地处理输入块。输出包含重复两到三次的单词。下面是完整的方法:

func sendAudio(audioFile: URL, completionHandler: @escaping (Bool, Bool, Data?)->Void) {

    createSession(){ sessionUrl, observeURL, session in
        let file = try! AVAudioFile(forReading: audioFile)
        let formatOfAudio = file.processingFormat
        self.engine = AVAudioEngine()
        guard let input = self.engine.inputNode else {
            print("no input")
            return
        }
        //The audio in format in this case is: <AVAudioFormat 0x61800009d010:  2 ch,  44100 Hz, Float32, non-inter>
        let formatIn = formatOfAudio
        let formatOut = AVAudioFormat(commonFormat: .pcmFormatInt16, sampleRate: 16000, channels: 1, interleaved: true)
        let mixer = AVAudioMixerNode()
        self.engine.attach(mixer)
        mixer.volume = 0.0
        self.engine.attach(self.audioPlayerNode)
        self.engine.connect(self.audioPlayerNode, to: mixer, format: formatIn)
        self.engine.connect(input, to: mixer, format: input.outputFormat(forBus: 0))
        self.engine.connect(mixer, to: self.engine.mainMixerNode, format: formatIn)
        let audioConverter = AVAudioConverter(from: formatIn, to: formatOut)
        mixer.installTap(onBus: 0, bufferSize: 32000, format: formatIn, block: {
            (buffer: AVAudioPCMBuffer!, time: AVAudioTime!) -> Void in
                let convertedBuffer = AVAudioPCMBuffer(pcmFormat: formatOut, frameCapacity: buffer.frameCapacity)
                let inputBlock: AVAudioConverterInputBlock = { inNumPackets, outStatus in
                    outStatus.pointee = AVAudioConverterInputStatus.haveData
                    return buffer
                }
                var error: NSError? = nil
                let status = audioConverter.convert(to: convertedBuffer, error: &error, withInputFrom: inputBlock)
                let myData = convertedBuffer.toData()
                completionHandler(true, false, myData)
        })
        self.audioPlayerNode.scheduleFile(file, at: nil){
            self.delayWithSeconds(3.0){
            self.engine.stop()
            mixer.removeTap(onBus: 0)
            completionHandler(true, true, nil)
            }
        }
        do {
            try self.engine.start()
        } catch {
            print(error)
        }
        self.audioPlayerNode.play()
    }
}

有什么想法吗?我从一个苹果幻灯片样本:

// Create an input block that’s called when converter needs input
let inputBlock : AVAudioConverterInputBlock = {inNumPackets, outStatus in 
    if (<no_data_available>) {   
        outStatus.memory = AVAudioConverterInputStatus.NoDataNow; 
        return nil;  
    } else if (<end_of_stream>) {   
        outStatus.memory = AVAudioConverterInputStatus.EndOfStream; 
        return nil;  
    } else {
        ..outStatus.memory = AVAudioConverterInputStatus.HaveData;   
        return inBuffer; // fill and return input buffer 
    }  
}

对于任何发现此问题的人来说,真正的根本原因是错误使用AVAudioConverterInputBlock。目标缓冲区容量并不重要,只要它足够大即可,但是该块将被重复调用,直到目标缓冲区被填满。

如果您的源缓冲区包含ABC,它将填充目的地ABCABCABC...。然后,如果您将其传输到实时播放,则块会被随机切断以适应播放时间,从而导致这种奇怪的裂纹。

实际的解决办法是正确设置AVAudioConverterInputStatus to .noDataNow一旦缓冲区被提交给转换器。请注意返回.endOfStream将永远锁定转换器对象。

var gotData = false
self.converter.convert(to: convertedBuffer, error: nil, withInputFrom: { (_, outStatus) -> AVAudioBuffer? in
    if gotData {
        outStatus.pointee = .noDataNow
        return nil
    }
    gotData = true
    outStatus.pointee = .haveData
    return inputBuffer
})            
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

带有 AVAudioConverterInputBlock 的 AVAudioConverter 在处理后会出现音频断断续续的情况 的相关文章

随机推荐

  • 如何一起使用 Angular 1.3.4 和 Angular 2 [重复]

    这个问题在这里已经有答案了 我已经有一个基于 Angular 1 3 4 构建的应用程序 我想将其更改为 Angular 2 但模块明智 假设我的页面上有 5 个模块 我想将一个模块迁移到 Angular 2 其他模块应该像以前的 1 3
  • 将下拉菜单选择保存在 cookie 中?

    我已经看过这个帖子好几次了 但我根本无法让代码工作 我需要帮助让这个下拉菜单将其设置保存到 cookie 这样当用户再次访问该网站时 他们之前的选择就会被保留 落下
  • Snakemake:使用run指令时如何实现log指令?

    Snakemake 允许为每个规则创建日志log参数指定日志文件的名称 通过管道传输结果相对简单shell输出到此日志 但我无法找出记录输出的方法run输出 即 python 脚本 一种解决方法是将 python 代码保存在脚本中 然后从
  • 链接服务器性能和选项

    在工作中 我们有两台服务器 其中一台正在运行很多人使用的应用程序 该应用程序具有 SQL Server 2000 后端 我很长时间以来都可以自由地查询它 但无法向其中添加任何内容 例如存储过程或额外的表 这导致我们将第二个 SQL Serv
  • 为什么 std::reference_wrapper 在调用成员函数时不隐式转换为引用? [复制]

    这个问题在这里已经有答案了 我不明白为什么不能使用std reference wrapper像这样 include
  • 开发 iPhone 应用程序以在 iPad 上运行 - 自动设置 2x

    有没有一种方法可以以编程方式将 iPad 设置为在 iPhone 应用程序启动时以 2 倍的速度运行 但仍保持 iPhone 应用程序本机 我知道我可以为每个硬件平台创建 NIB 文件 但为了方便起见 我只是希望应用程序启动就像用户在 iP
  • Scheme 可以将列表扩展为参数吗?

    考虑到我有一个程序 plus x y 女巫正好需要两个参数 现在我还有一个列表 其中包含两个对象 例如 list 1 2 那么 如果有any将列表扩展为两个参数的神奇方法 我们有一个点概念版本 但是那个isn t我想要的是 我只是想扩展该列
  • 在 Eclipse 中打开 xml 文件时出现错误 [重复]

    这个问题在这里已经有答案了 在 Eclipse 中 当我打开具有相同数据的两个不同名称的 xml 文件 意味着 A 和 B 是 2 个 xml 文件 它们具有相同的数据 时 我在控制台中出现错误 我在控制台中收到以下错误 为什么会出现这个错
  • 如何将 buildapp 与 Quicklisp 结合使用

    我想使用 buildapp 来制作作为给出的curl lisp可执行文件example buildapp output lisp curl asdf path src clbuild systems load system drakma e
  • 自动发布回到 mvc 下拉列表中

    要求 我的视图页面上有一个下拉列表 显示供应商列表 从下拉列表中选择供应商后 页面将显示所选供应商的详细信息 默认情况下 我需要选择第一个供应商并显示其详细信息 我可以使用以下代码来完成此任务 问题 不知道如何实现自动回发 true在 MV
  • 我可以在一个 Web 应用程序中拥有两个 web.xml 文件吗?

    我可以拥有一个包含多个 web xml 文件的应用程序吗 并且两个应用程序可以有父子关系从而有两个web xml吗 对于低于 servlet 3 0 的版本 则不能 如果您使用的是 3 0 则有一个可能性 在 JSR 315 Java Se
  • Azure Powershell:获取服务的公共虚拟IP

    是否可以使用 powershell 获取 azure 服务的公共虚拟 IP VIP 一种方法是使用 Get AzureEndpoint 命令 Get AzureVM Name thevmname ServiceName theservice
  • 面向对象的c++ win32?

    我想创建自己的类来处理创建窗口和窗口过程 但我注意到窗口过程必须是静态的 我现在想知道是否可以使窗口过程面向对象 我读过一些关于面向对象窗口的教程 但它们总是使过程静态 那有什么用 任何有关如何解决此问题的链接或信息将不胜感激 thanks
  • 如何在数据库中存储图像的位置?

    我有一个颜色列表 其中包含我想要向特定用户显示的纹理 因此我需要加载特定用户拥有的颜色的图像 颜色的信息包含在 ObjecDTO 中 其中一个属性是其图像小路 我的问题是我应该如何在数据库中存储图像路径 是否有任何特殊规则 例如 由于数据库
  • Spring Batch“默认”上下文变量是什么?

    In the 春季批次步进范围文档 存在三个无法解释的 spring batch 上下文映射 jobParameters jobExecutionContext and stepExecutionContext Springsource示例
  • MVC 自定义路由中的多个级别

    我正在尝试构建自己的小cms 我创建了一个抽象 pageBase 类 由 Static Reviews Articles News 继承 每个都有自己的控制器方法 我的问题是我需要允许管理员定义他自己的自定义路径级别 例如 news loc
  • 从字符串中提取格式不一致的日期(日期解析,NLP)

    我有一个很大的文件列表 其中一些文件名中嵌入了日期 日期的格式不一致且通常不完整 例如 Aug06 Aug2006 August 2006 08 06 01 08 06 2006 011004 等 除此之外 某些文件名具有不相关的数字 看起
  • 多线程和多进程的性能差异

    几年前 在Windows环境下 我做了一些测试 让CPU计算密集型 内存访问密集型 I O访问密集型应用程序的多个实例运行 我开发了2个版本 一个是在多处理下运行 另一个是在多线程下运行 我发现多处理的性能要好得多 我在其他地方读过 但我不
  • window.history.back() 不起作用。

    我无法让它发挥作用 我已经尝试了很多年了 请帮我
  • 带有 AVAudioConverterInputBlock 的 AVAudioConverter 在处理后会出现音频断断续续的情况

    我正在尝试将音频缓冲区转换为不同的格式 并且我正在使用 AVAudioConverter 当您具有相同的采样率并且不需要使用 AVAudioConverterInputBlock 时 AVAudioConverter 会完成这项工作 但如果