2017-03-08 23 views
5

此方法处理来自AVAudioEngine的输入节点上installTap的回调。我已经证实我得到单声道float32/48000hz缓冲区数据,并且我想将它转换为单声道int16/16000hz。AVAudioConverter float32/48khz - > int16/16khz转换失败

var converter: AVAudioConverter? = nil 
var convertBuffer: AVAudioPCMBuffer? = nil 
let targetFormat = AVAudioFormat(commonFormat: AVAudioCommonFormat.pcmFormatInt16, sampleRate: 16000, channels: 1, interleaved: false) 

func recordCallback(buffer: AVAudioPCMBuffer, time: AVAudioTime) { 
    if converter == nil { 
     convertBuffer = AVAudioPCMBuffer(pcmFormat: targetFormat, frameCapacity: buffer.frameCapacity) 
     convertBuffer?.frameLength = convertBuffer!.frameCapacity 
     converter = AVAudioConverter(from: buffer.format, to: convertBuffer!.format) 
     converter?.sampleRateConverterAlgorithm = AVSampleRateConverterAlgorithm_Normal 
     converter?.sampleRateConverterQuality = .max 
    } 

    guard let convertBuffer = convertBuffer else { return } 

    log.info("Converter: \(self.converter!)") 
    log.info("Converter buffer: \(self.convertBuffer!)") 
    log.info("Converter buffer format: \(self.convertBuffer!.format)") 
    log.info("Source buffer: \(buffer)") 
    log.info("Source buffer format: \(buffer.format)") 

    do { 
     try converter!.convert(to: convertBuffer, from: buffer) 
    } catch let error { 
     log.error("Conversion error: \(error)") 
     observer?.onError(EngineRecordTaskError.ConversionError(error: error)) 
     return 
    } 

    … 
} 

这给了我有用的错误:

Conversion error: Error Domain=NSOSStatusErrorDomain Code=-50 "(null)" 

如果我用另一种方法.convert(到:错误:withInputFrom :),它不填充NSError,不填目标缓冲区 - 无提示失败。

已记录信息:

Converter: <AVAudioConverter: 0x17001cd40> 
Converter buffer: <[email protected]: 9600/9600 bytes> 
Converter buffer format: <AVAudioFormat 0x17448ba90: 1 ch, 16000 Hz, Int16> 
Source buffer: <[email protected]: 19200/19200 bytes> 
Source buffer format: <AVAudioFormat 0x174480910: 1 ch, 48000 Hz, Float32> 
Conversion error: Error Domain=NSOSStatusErrorDomain Code=-50 "(null)" 

从调试器附加信息:

(lldb) po buffer.frameCapacity 
4800 

(lldb) po convertBuffer.frameCapacity 
4800 

(lldb) po buffer.frameLength 
4800 

(lldb) po convertBuffer.frameLength 
4800 

下面是转换的替代代码我想:

var conversionError: NSError? = nil 
    converter!.convert(to: convertBuffer, error: &conversionError, withInputFrom: { (_, _) in 
     return buffer 
    }) 

    if let conversionError = conversionError { 
     log.error("Conversion error: \(conversionError)") 
     observer?.onError(EngineRecordTaskError.ConversionError(error: conversionError)) 
     return 
    } 

回答

2

convert头中的讨论file:

The output buffer's frameCapacity should be at least at large as the inputBuffer's frameLength. If the conversion involves a codec or sample rate conversion, you instead must use convertToBuffer:error:withInputFromBlock:.

你从48kHz的达16kHz,其算作一个速率转换转换,所以你必须使用convertToBuffer

let inputBlock: AVAudioConverterInputBlock = { inNumPackets, outStatus in 
    outStatus.pointee = AVAudioConverterInputStatus.haveData 
    return buffer 
} 

var error: NSError? = nil 
let status: AVAudioConverterOutputStatus = converter!.convert(to: convertBuffer, error: &error, withInputFrom: inputBlock) 
// TODO: check status 

附:在苹果上创建新的NSError代码必须非常昂贵 - 它们的预算不能涵盖“速率转换需要convertToBuffer”的消息。

+0

设置outStatus上次尝试convertToBuffer方法时错过了什么。谢谢! –