2

I'm trying to record some audio using AVAudioEngine, but when I start recording with the methods that I have in my setup class, the app crashes and gives me some error, like the following:

2021-07-15 21:28:27.569564-0400 App[75861:6634462] [avae]            AVAEInternal.h:88    required condition is false: [AVAudioEngineGraph.mm:1357:Initialize: (IsFormatSampleRateAndChannelCountValid(outputHWFormat))]
2021-07-15 21:28:27.569679-0400 App[75861:6634462] [avae]          AVAudioEngine.mm:167   Engine@0x282ad0de0: could not initialize, error = -10875
2021-07-15 21:28:27.571773-0400 App[75861:6634462] Audio files cannot be non-interleaved. Ignoring setting AVLinearPCMIsNonInterleaved YES.
2021-07-15 21:28:27.575892-0400 App[75861:6634462] [avae]            AVAEInternal.h:88    required condition is false: [AVAudioEngineGraph.mm:1357:Initialize: (IsFormatSampleRateAndChannelCountValid(outputHWFormat))]

This is the structure that I'm using to make the recording using AVAudioEngine:

class Recorder {
  
    enum RecordingState {
        case recording, paused, stopped
    }
  
    private var engine: AVAudioEngine!
    private var mixerNode: AVAudioMixerNode!
    private var state: RecordingState = .stopped
  
  
    init() {
        setupSession()
        setupEngine()
    }
    
    fileprivate func setupSession() {
        let session = AVAudioSession.sharedInstance()
        try? session.setCategory(.record)
        try? session.setActive(true, options: .notifyOthersOnDeactivation)
    }
    
    fileprivate func setupEngine() {
        
        engine = AVAudioEngine()
        mixerNode = AVAudioMixerNode()
        
        mixerNode.volume = 0
        
        engine.attach(mixerNode)
        makeConnections()
        
        engine.prepare()
    }

    fileprivate func makeConnections() {
      let inputNode = engine.inputNode
      let inputFormat = inputNode.outputFormat(forBus: 0)
      engine.connect(inputNode, to: mixerNode, format: inputFormat)

      let mainMixerNode = engine.mainMixerNode
      let mixerFormat = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: inputFormat.sampleRate, channels: 1, interleaved: false)
      engine.connect(mixerNode, to: mainMixerNode, format: mixerFormat)
        
    }
    
    func startRecording() throws {
      let tapNode: AVAudioNode = mixerNode
      let format = tapNode.outputFormat(forBus: 0)

      let documentURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
      
      let file = try AVAudioFile(forWriting: documentURL.appendingPathComponent("recording.caf"), settings: format.settings)

      tapNode.installTap(onBus: 0, bufferSize: 4096, format: format, block: {
        (buffer, time) in
        try? file.write(from: buffer)
      })

      try engine.start()
      state = .recording
    }
    
    func stopRecording() {
      mixerNode.removeTap(onBus: 0)
      
      engine.stop()
      state = .stopped
    }
} 

And this is how I'm calling the class to start recording:

let hola = Recorder()
do {
   try hola.startRecording()
} catch { }
Edward Pizzurro
  • 575
  • 4
  • 15

0 Answers0