2015-11-25 9 views
6

Ich habe zwei Klassen, MicrophoneHandler und AudioPlayer. Ich habe es geschafft AVCaptureSession zu verwenden Mikrofondaten mit der genehmigten Antwort here tippen, und und konvertiert die CMSampleBuffer-NSData mit dieser Funktion:Wiedergabe von AVAudioPCMBuffer mit 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) 
} 

Ich möchte nun den Ton über den Lautsprecher spielen, indem sie die NSData Umwandlung erzeugt oben zu AVAudioPCMBuffer und spielen Sie es mit AVAudioEngine. Meine AudioPlayer Klasse ist wie folgt:

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 
} 

Der Puffer erreicht die handleBuffer:buffer Funktion, wenn self.delegate.handleBuffer(result) oben im ersten Schnipsel genannt wird.

Ich kann print(newBuffer), und sehen Sie die Speicherplätze der konvertierten Puffer, aber nichts kommt aus den Lautsprechern. Ich kann mir nur vorstellen, dass zwischen den Konvertierungen zu und von NSData etwas nicht konsistent ist. Irgendwelche Ideen? Danke im Voraus.

Antwort

1

überspringen die rohe NSData Format

Warum nicht AVAudioPlayer den ganzen Weg? Wenn Sie unbedingt NSData benötigen, können Sie solche Daten immer von der folgenden soundURL laden. In diesem Beispiel ist der Plattenpuffer so etwas wie:

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

Es macht Sinn, direkt auf eine Datei trotzdem für eine optimale Speicher- und Ressourcenmanagement zu erfassen. Sie erhalten NSData von Ihrer Aufnahme auf diese Weise:

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

Der folgende Code ist alles, was Sie brauchen:

Bilanz

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

Wiedergabe

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 {} 

Einstellungen

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

Herunterladen Xcode Projekt:

Sie können diese sehr Beispiel here finden. Laden Sie das vollständige Projekt, das sowohl Simulator als auch Gerät aufzeichnet und wiedergibt, unter Swift Recipes herunter.

+0

Wir benötigen das NSData-Rohformat, um es über einen Socket zu übertragen. Wir streamen Audio. –

+0

Datei zu 'NSData' kommt aus der Box. Kannst du dir die Datei nur als Puffer vorstellen? Es ist zufällig ein Plattenpuffer, aber es ist immer noch nur ein Puffer? – SwiftArchitect

+0

Wie löschen wir den Puffer jedes Mal, wenn wir ein Paket mit NSData über den Socket senden? @SwiftArchitect –