2015-11-25 15 views
6

Ho due classi, MicrophoneHandler e AudioPlayer. Sono riuscito a utilizzare AVCaptureSession di attingere i dati microfono usando la risposta approvato here, ed e convertito il CMSampleBuffer-NSData utilizzare questa funzione:Riproduci audio da AVAudioPCMBuffer con AVAudioEngine

func sendDataToDelegate(buffer: CMSampleBuffer!) 
{ 
    let block = CMSampleBufferGetDataBuffer(buffer) 
    var length = 0 
    var data: UnsafeMutablePointer<Int8> = nil 

    var status = CMBlockBufferGetDataPointer(block!, 0, nil, &length, &data) // TODO: check for errors 

    let result = NSData(bytesNoCopy: data, length: length, freeWhenDone: false) 

    self.delegate.handleBuffer(result) 
} 

Vorrei ora per riprodurre l'audio attraverso l'altoparlante convertendo la NSData prodotta sopra a AVAudioPCMBuffer e riprodurlo usando AVAudioEngine. La mia classe AudioPlayer è il seguente:

var engine: AVAudioEngine! 
var playerNode: AVAudioPlayerNode! 
var mixer: AVAudioMixerNode! 

override init() 
{ 
    super.init() 

    self.setup() 
    self.start() 
} 

func handleBuffer(data: NSData) 
{ 
    let newBuffer = self.toPCMBuffer(data) 
    print(newBuffer) 

    self.playerNode.scheduleBuffer(newBuffer, completionHandler: nil) 
} 

func setup() 
{ 
    self.engine = AVAudioEngine() 
    self.playerNode = AVAudioPlayerNode() 

    self.engine.attachNode(self.playerNode) 
    self.mixer = engine.mainMixerNode 

    engine.connect(self.playerNode, to: self.mixer, format: self.mixer.outputFormatForBus(0)) 
} 

func start() 
{ 
    do { 
     try self.engine.start() 
    } 
    catch { 
     print("error couldn't start engine") 
    } 

    self.playerNode.play() 
} 

func toPCMBuffer(data: NSData) -> AVAudioPCMBuffer 
{ 
    let audioFormat = AVAudioFormat(commonFormat: AVAudioCommonFormat.PCMFormatFloat32, sampleRate: 8000, channels: 2, interleaved: false) // given NSData audio format 
    let PCMBuffer = AVAudioPCMBuffer(PCMFormat: audioFormat, frameCapacity: UInt32(data.length)/audioFormat.streamDescription.memory.mBytesPerFrame) 

    PCMBuffer.frameLength = PCMBuffer.frameCapacity 

    let channels = UnsafeBufferPointer(start: PCMBuffer.floatChannelData, count: Int(PCMBuffer.format.channelCount)) 

    data.getBytes(UnsafeMutablePointer<Void>(channels[0]) , length: data.length) 

    return PCMBuffer 
} 

Il buffer raggiunge la funzione handleBuffer:buffer quando self.delegate.handleBuffer(result) è chiamato nel primo pezzo sopra.

Sono in grado di print(newBuffer) e di visualizzare le posizioni di memoria dei buffer convertiti, ma non esce nulla dagli altoparlanti. Posso solo immaginare che qualcosa non sia coerente tra le conversioni da e verso NSData. Qualche idea? Grazie in anticipo.

risposta

1

saltare la NSData formato raw

Perché non usare AVAudioPlayer tutta la strada? Se hai effettivamente bisogno di NSData, puoi sempre caricare tali dati dal soundURL qui sotto. In questo esempio, il buffer del disco è qualcosa di simile:

let soundURL = documentDirectory.URLByAppendingPathComponent("sound.m4a") 

Ha senso per registrare direttamente in un file in ogni caso per la memoria e la gestione ottimale delle risorse. Si ottiene NSData dalla vostra registrazione in questo modo:

let data = NSFileManager.defaultManager().contentsAtPath(soundURL.path()) 

Il codice qui sotto è tutto ciò che serve:

Record

if !audioRecorder.recording { 
    let audioSession = AVAudioSession.sharedInstance() 
    do { 
     try audioSession.setActive(true) 
     audioRecorder.record() 
    } catch {} 
} 

Giocare

if (!audioRecorder.recording){ 
    do { 
     try audioPlayer = AVAudioPlayer(contentsOfURL: audioRecorder.url) 
     audioPlayer.play() 
    } catch {} 
} 

Setup

let audioSession = AVAudioSession.sharedInstance() 
do { 
    try audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord) 
    try audioRecorder = AVAudioRecorder(URL: self.directoryURL()!, 
     settings: recordSettings) 
    audioRecorder.prepareToRecord() 
} catch {} 

Impostazioni

let recordSettings = [AVSampleRateKey : NSNumber(float: Float(44100.0)), 
    AVFormatIDKey : NSNumber(int: Int32(kAudioFormatMPEG4AAC)), 
    AVNumberOfChannelsKey : NSNumber(int: 1), 
    AVEncoderAudioQualityKey : NSNumber(int: Int32(AVAudioQuality.Medium.rawValue))] 

download Xcode Progetto:

Potete trovare questo esempio here. Scarica il progetto completo, che registra e riproduce sia sul simulatore che sul dispositivo, da Swift Recipes.

+0

Abbiamo bisogno del formato raw NSData per trasmetterlo tramite un socket. Stiamo streaming audio. Il file –

+0

in 'NSData' viene fornito immediatamente. Riesci a pensare al file come a un buffer? Capita di essere un buffer del disco, ma è ancora solo un buffer? – SwiftArchitect

+0

Come si cancella il buffer ogni volta che si invia un pacchetto di NSData tramite il socket? @SwiftArchitect –

Problemi correlati