2015-11-25 125 views
6

我有两个类,MicrophoneHandlerAudioPlayer。我已成功地使用AVCaptureSession以核定答案here挖掘麦克风的数据,并使用此功能转换的CMSampleBufferNSData使用AVAudioEngine播放AVAudioPCMBuffer的音频

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

我现在想通过转换所产生的NSData打在扬声器的音频以上至AVAudioPCMBuffer并使用AVAudioEngine进行播放。我的AudioPlayer类如下:

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 
} 

缓冲到达时self.delegate.handleBuffer(result)是所谓的第一片段上方的handleBuffer:buffer功能。

我可以print(newBuffer),并查看转换后的缓冲区的内存位置,但没有任何内容从扬声器中传出。我只能想象出NSData之间的转换不一致。有任何想法吗?提前致谢。

回答

1

跳过原NSData格式

为什么不使用AVAudioPlayer一路?如果您肯定需要NSData,则始终可以从下面的soundURL加载此类数据。在这个例子中,磁盘缓存是一样的东西:

​​

这是有道理的直接反正最佳的内存和资源管理记录到文件中。你得到NSData从您的记录是这样的:

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

下面的代码是你所需要的:

记录

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

播放

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

设置

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

设置

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

下载Xcode项目:

你可以找到这个非常例子here。从Swift Recipes下载完整的项目,它可以在模拟器和设备上进行记录和播放。

+0

我们需要NSData原始格式通过套接字传输它。我们正在传输音频。从'盒子'出来的' –

+0

'文件到'NSData'。你可以把文件看作是一个缓​​冲区吗?它恰好是一个磁盘缓冲区,但它仍然只是一个缓冲区? – SwiftArchitect

+0

每当我们通过套接字发送一个NSData数据包时,我们如何清除缓冲区? @SwiftArchitect –