2015-11-25 2 views
6

У меня есть два класса: MicrophoneHandler и AudioPlayer. Мне удалось использовать AVCaptureSession задействовать данные микрофона, используя утвержденный ответ here, а и преобразовал CMSampleBuffer в NSData с помощью этой функции:Воспроизведение аудио с AVAudioPCMBuffer с 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) 
} 

Теперь я хотел бы играть звук через динамик, преобразуя 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 
} 

буфер достигает функции handleBuffer:bufferself.delegate.handleBuffer(result) когда вызывается в первом фрагменте кода выше.

Я могу print(newBuffer) и видеть места памяти преобразованных буферов, но ничего не выходит из динамиков. Я могу только представить, что между преобразованиями и от NSData не существует. Есть идеи? Заранее спасибо.

ответ

1

Пропустить сырьевая NSData формат

Почему бы не использовать AVAudioPlayer весь путь? Если вам действительно нужно NSData, вы всегда можете загрузить такие данные с soundURL ниже. В этом примере, буфер диска что-то вроде:

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

Это имеет смысл записывать непосредственно в файл в любом случае для оптимальной памяти и управления ресурсами. Вы получаете NSData из вашей записи таким образом:

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

ниже код все, что вам нужно:

Запись

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

Play

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

Вы можете найти этот самый пример here. Загрузите полный проект, который записывает и воспроизводит как на симуляторе, так и на устройстве, от Swift Recipes.

+0

Нам нужен необработанный формат NSData для его передачи через сокет. Мы передаем аудио. –

+0

Файл 'NSData' выходит из коробки. Можете ли вы представить файл как просто буфер? Это, конечно, дисковый буфер, но все же это всего лишь буфер? – SwiftArchitect

+0

Как очистить буфер каждый раз, когда мы отправляем пакет NSData через сокет? @SwiftArchitect –

Смежные вопросы