gpt4 book ai didi

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

转载 作者:搜寻专家 更新时间:2023-10-31 08:30:20 26 4
gpt4 key购买 nike

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

但如果我处理相同的采样率,我的音频数据就会出现奇怪的断断续续。我有一种感觉,我没有很好地处理输入 block 。输出有重复两到三遍的单词。以下是完整的方法:

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

有什么想法吗?我从 Apple slide sample 得到了这段代码:

// 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 的不正确使用。目标缓冲区容量并不重要,只要它足够大即可,但是将重复调用该 block ,直到目标缓冲区被填满。

如果您的源缓冲区包含 ABC,它将用 ABCABCABC... 填充目标。然后,如果您将其通过管道传输到实时播放, block 将被随机切断以适应播放时间,从而导致这种奇怪的爆裂声。

实际的解决方案是在缓冲区提交给转换器后将 AVAudioConverterInputStatus 正确设置为 .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
})

关于swift - 带有 AVAudioConverterInputBlock 的 AVAudioConverter 在处理后会出现断断续续的音频,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44792936/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com