My writing the installTap buffer to an AVAudioFile seems to fail data-wise, or at the end

I am trying to save the buffer from my installTap to a file. I do it in chunks of 10 so I'll get a bigger file. When I try to play the written file (from the simulator's directory) QuickTime says that it's not compatible.

I have examined the bad m4a file and a working one. There are a lot of zero's in the bad file at the beginning followed by a lot of data. However both files appears to have the same header.

A lot of people mention that I have to nil the AudioFile, but:

audioFile = nil

is not a valid syntax, nor can I file a close method in AudioFile.

Here's the complete code, edited into one working file:

import UIKit
import AVFoundation

class ViewController: UIViewController {
    let audioEngine = AVAudioEngine()
    var audioFile = AVAudioFile()
    var x = 0


    override func viewDidLoad() {
        super.viewDidLoad()
        record()
        // Do any additional setup after loading the view.
    }

    func makeFile(format: AVAudioFormat) {
        let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
        do {
            _ = try FileManager.default.contentsOfDirectory(at: paths!, includingPropertiesForKeys: nil)
        } catch { print ("error")}
        let destinationPath = paths!.appendingPathComponent("audioT.m4a")
        print ("\(destinationPath)")
        do {
            audioFile = try AVAudioFile(forWriting: destinationPath,
                                            settings: format.settings)

            print ("file created")
        } catch { print ("error creating file")}
    }
    
    func record(){
        let node = audioEngine.inputNode
        let recordingFormat = node.inputFormat(forBus: 0)
        makeFile(format: recordingFormat)
        
        
        node.installTap(onBus: 0, bufferSize: 8192, format: recordingFormat, block: { [self]
            
            (buffer, _) in
            do {
                try audioFile.write(from: buffer);
            print ("buffer filled");
                x += 1;
                print("wrote \(x)")
                if x > 9 {
                    endThis()
                }
            } catch {return};})
        
        audioEngine.prepare()
        do {
            try audioEngine.start()
        } catch let error {
            print ("oh catch")
        }
    }
    
    func endThis(){
        audioEngine.stop()
        audioEngine.inputNode.removeTap(onBus: 0)
    }
}
Answered by SergioDCQ in 701261022

It's kind of kludgy but someone gave me the answer here:

https://stackoverflow.com/questions/70616820/my-writing-the-installtap-buffer-to-an-avaudiofile-seems-to-fail-data-wise/70618216?noredirect=1#comment124895854_70618216

You need to let your AVAudioFile go out of scope (nil it at some point), that's how you call AVAudioFile's close() method, which presumably finishes writing out header information.

Accepted Answer

It's kind of kludgy but someone gave me the answer here:

https://stackoverflow.com/questions/70616820/my-writing-the-installtap-buffer-to-an-avaudiofile-seems-to-fail-data-wise/70618216?noredirect=1#comment124895854_70618216

You need to let your AVAudioFile go out of scope (nil it at some point), that's how you call AVAudioFile's close() method, which presumably finishes writing out header information.

My writing the installTap buffer to an AVAudioFile seems to fail data-wise, or at the end
 
 
Q