2017-03-08 76 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方法時錯過了什麼。謝謝! –