Search code examples
swiftmacosswiftuiavfoundationavaudioplayer

Playback audio failed on macOS using swift language


Goal: Play .m4a audio file that was recorded on mic

Following code is to record audio from mic

public func startRecording() {
        let input = audioEngine.inputNode
        let bus = 0
        let inputFormat = input.inputFormat(forBus: bus)
        
        let outputURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("recorded123.m4a")
        print("writing to \(outputURL)")
        do {
            outputFile = try AVAudioFile(forWriting: outputURL, settings: inputFormat.settings, commonFormat: inputFormat.commonFormat, interleaved: inputFormat.isInterleaved)
            
            input.installTap(onBus: bus, bufferSize: 512, format: inputFormat) { (buffer, time) in
                try? self.outputFile?.write(from: buffer)
            }
            
            try audioEngine.start()
            recording = true
        } catch {
            print(error)
        }
    }

Following code is to playback the recorded audio

func startPlayback(audio: URL) {
        do {
            audioPlayer = try AVAudioPlayer(contentsOf: audio)
            audioPlayer.delegate = self
            audioPlayer.play()
            
            isPlaying = true
        } catch {
            print("Playback failed \(error.localizedDescription)")
        }
    }

The above code works for .caf filetype but when I changed it to .m4a type it fails to play and prints Playback failed The operation couldn’t be completed. (OSStatus error 1685348671.)

Any help is highly appreciated

My assumption is that the audio is not properly recorded in startRecording method


Solution

  • Make sure you are recording the audio in the correct format:

    To specify the output file type as .m4a, you should configure the output format settings accordingly. Here's how you can modify the startRecording function:

    public func startRecording() {
        let input = audioEngine.inputNode
        let bus = 0
        let inputFormat = input.inputFormat(forBus: bus)
        
        let outputURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("recorded123.m4a")
        print("writing to \(outputURL)")
        
        let outputFormatSettings: [String: Any] = [
            AVFormatIDKey: kAudioFormatMPEG4AAC,
            AVEncoderBitRateKey: 320000,
            AVNumberOfChannelsKey: 2,
            AVSampleRateKey: 44100.0
        ]
    
        do {
            outputFile = try AVAudioFile(forWriting: outputURL, settings: outputFormatSettings)
            
            input.installTap(onBus: bus, bufferSize: 512, format: inputFormat) { (buffer, time) in
                try? self.outputFile?.write(from: buffer)
            }
            
            try audioEngine.start()
            recording = true
        } catch {
            print(error)
        }
    }