2017-03-08 1 views
5

Cette méthode gère le callback de installTap sur le noeud d'entrée à partir d'un AVAudioEngine. J'ai confirmé que j'obtiens des données de tampon mono float32/48000hz, et je voudrais le convertir en mono int16/16000hz.Echec de conversion 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 
    } 

    … 
} 

Cela me donne l'erreur utile:

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

Si j'utilise la méthode alternative .convert (à: erreur: withInputFrom :), il ne remplit pas le NSError, et ne remplit pas les cible buffer - échoue silencieusement.

information enregistrée:

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

Informations complémentaires du débogueur:

(lldb) po buffer.frameCapacity 
4800 

(lldb) po convertBuffer.frameCapacity 
4800 

(lldb) po buffer.frameLength 
4800 

(lldb) po convertBuffer.frameLength 
4800 

Voici le code alternatif pour la conversion J'ai essayé:

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 
    } 

Répondre

2

De la discussion de convert dans l'en-tête fichier:

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:.

Vous conversion de 48 kHz à 16 kHz, qui compte comme une conversion de taux, vous devez utiliser 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 

P.S. il doit être très coûteux de créer de nouveaux codes à la pomme - leur budget ne pouvait pas couvrir un message "conversion rate requires convertToBuffer".

+0

Définir le statut outStatus ce que j'ai manqué lorsque j'ai essayé l'approche convertToBuffer la dernière fois. Merci! –