No se puede reproducir audio grabado de voz utilizando AVCaptureAudioDataOutputSampleDelegate

He estado buscando en Google e investigando durante días, pero parece que esto no funciona y no encuentro ninguna solución en Internet.

Estoy tratando de capturar mi voz con el micrófono y luego reproducirlo a través de los parlantes.

Aquí está mi código:

class ViewController: UIViewController, AVAudioRecorderDelegate, AVCaptureAudioDataOutputSampleBufferDelegate { var recordingSession: AVAudioSession! var audioRecorder: AVAudioRecorder! var captureSession: AVCaptureSession! var microphone: AVCaptureDevice! var inputDevice: AVCaptureDeviceInput! var outputDevice: AVCaptureAudioDataOutput! override func viewDidLoad() { super.viewDidLoad() recordingSession = AVAudioSession.shanetworkingInstance() do{ try recordingSession.setCategory(AVAudioSessionCategoryPlayAndRecord) try recordingSession.setMode(AVAudioSessionModeVoiceChat) try recordingSession.setPrefernetworkingSampleRate(44000.00) try recordingSession.setPrefernetworkingIOBufferDuration(0.2) try recordingSession.setActive(true) recordingSession.requestRecordPermission() { [unowned self] (allowed: Bool) -> Void in DispatchQueue.main.async { if allowed { do{ self.microphone = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeAudio) try self.inputDevice = AVCaptureDeviceInput.init(device: self.microphone) self.outputDevice = AVCaptureAudioDataOutput() self.outputDevice.setSampleBufferDelegate(self, queue: DispatchQueue.main) self.captureSession = AVCaptureSession() self.captureSession.addInput(self.inputDevice) self.captureSession.addOutput(self.outputDevice) self.captureSession.startRunning() } catch let error { print(error.localizedDescription) } } } } }catch let error{ print(error.localizedDescription) } } 

Y la function de callback:

 func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) { var audioBufferList = AudioBufferList( mNumberBuffers: 1, mBuffers: AudioBuffer(mNumberChannels: 0, mDataByteSize: 0, mData: nil) ) var blockBuffer: CMBlockBuffer? var osStatus = CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer( sampleBuffer, nil, &audioBufferList, MemoryLayout<AudioBufferList>.size, nil, nil, UInt32(kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment), &blockBuffer ) do { var data: NSMutableData = NSMutableData.init() for i in 0..<audioBufferList.mNumberBuffers { var audioBuffer = AudioBuffer( mNumberChannels: audioBufferList.mBuffers.mNumberChannels, mDataByteSize: audioBufferList.mBuffers.mDataByteSize, mData: audioBufferList.mBuffers.mData ) let frame = audioBuffer.mData?.load(as: Float32.self) data.append(audioBuffer.mData!, length: Int(audioBuffer.mDataByteSize)) } var dataFromNsData = Data.init(referencing: data) var avAudioPlayer: AVAudioPlayer = try AVAudioPlayer.init(data: dataFromNsData) avAudioPlayer.prepareToPlay() avAudioPlayer.play() } } catch let error { print(error.localizedDescription) //prints out The operation couldn't be completed. (OSStatus error 1954115647.) } 

Cualquier ayuda con esto sería increíble y probablemente ayudaría a muchas otras personas, ya que hay muchas versiones rápidas incompletas de esto.

Gracias.

¡Estabas muy cerca! Estabas capturando audio en la didOutputSampleBuffer llamada didOutputSampleBuffer , pero esa es una callback de alta frecuencia por lo que estabas creando una gran cantidad de AVAudioPlayer y pasándolos por datos LPCM sin procesar, mientras que ellos solo saben cómo analizar los types de files CoreAudio y luego iban a salir del scope de todos modos .

Puede reproducir fácilmente los almacenamientos intermedios que está capturando con AVCaptureSession utilizando el AVAudioEngine AVAudioPlayerNode , pero en ese punto también puede usar AVAudioEngine para grabar también desde el micrófono:

 import UIKit import AVFoundation class ViewController: UIViewController { var engine = AVAudioEngine() override func viewDidLoad() { super.viewDidLoad() let input = engine.inputNode! let player = AVAudioPlayerNode() engine.attach(player) let bus = 0 let inputFormat = input.inputFormat(forBus: bus) engine.connect(player, to: engine.mainMixerNode, format: inputFormat) input.installTap(onBus: bus, bufferSize: 512, format: inputFormat) { (buffer, time) -> Void in player.scheduleBuffer(buffer) } try! engine.start() player.play() } }