Search code examples
swiftavfoundationavaudioplayeravaudiorecorder

iOS - Record an mp4 file


So i wanna generate an mp4 file when recording , what i am able to do is to generate only .m4a or .caf. when i am trying to generate other files it fails using this code:

import AVFoundation

class ViewController: UIViewController {
var fileName: String = "audioFile.m4a"

var soundRecorder: AVAudioRecorder?
var soundPlayer: AVAudioPlayer?
var audioSession = AVAudioSession.sharedInstance()

override func viewDidLoad() {
    super.viewDidLoad()
    setUpRecorder()
    playBtn.isEnabled = false

}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    self.audioSession = AVAudioSession.sharedInstance()

    do {
        try audioSession.setCategory(AVAudioSession.Category.playAndRecord, mode: .measurement, options: .defaultToSpeaker)
        try audioSession.setActive(true, options: .notifyOthersOnDeactivation)
    } catch {
        print(error)
    }
}


func getDocDirector() -> URL {
    let path = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
    return path[0]
}

func setUpRecorder() {


    let audioFileName = getDocDirector().appendingPathComponent(fileName)
    let recordSettings = [ AVFormatIDKey: Int(kAudioFormatAppleLossless),
                           AVEncoderAudioQualityKey: AVAudioQuality.max.rawValue,
                           AVEncoderBitRateKey: 192000,
                           AVNumberOfChannelsKey: 1,
    AVSampleRateKey: 441000 ] as [String: Any]

    do {
        soundRecorder = try AVAudioRecorder(url: audioFileName, settings: recordSettings)
        soundRecorder?.delegate = self
        soundRecorder?.prepareToRecord()
    } catch {
       print(error)
    }
}

func setUpPlayer() {
    let audioFileName = getDocDirector().appendingPathComponent(fileName)
    do {
        soundPlayer = try AVAudioPlayer(contentsOf: audioFileName)
        soundPlayer?.delegate = self
        soundPlayer?.prepareToPlay()
        soundPlayer?.volume = 1.0
    } catch {
        print(error)
    }
}

@IBAction func recordAction(_ sender: Any) {
    if recordBtn.titleLabel?.text == "Record" {
        soundRecorder?.record()
        recordBtn.setTitle("Stop", for: .normal)
        playBtn.isEnabled = false
    } else {
        soundRecorder?.stop()
        recordBtn.setTitle("Record", for: .normal)
        playBtn.isEnabled = false
    }
}

@IBAction func playAction(_ sender: Any) {
    if playBtn.titleLabel?.text == "Play" {
        playBtn.setTitle("Stop", for: .normal)
        recordBtn.isEnabled = false
        setUpPlayer()
        soundPlayer?.play()
    } else {
        playBtn.setTitle("Play", for: .normal)
        recordBtn.isEnabled = false
    }
}

extension ViewController: AVAudioRecorderDelegate {
 func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {
    playBtn.isEnabled = true
}

func audioRecorderEncodeErrorDidOccur(_ recorder: AVAudioRecorder, error: Error?) {
    print(error!)
}
}

extension ViewController: AVAudioPlayerDelegate {  
 func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
    recordBtn.isEnabled = true
    playBtn.setTitle("Play", for: .normal)
}
}

So all of this works great yet i cant manage to find the way to write mp4 Is there any way to write straight mp4? my end goal is to generate fragmented mp4 to send through sockets... be glad for an advice


Solution

  • Change your settings dictionary to this one:

    let recordSettings: [String: Any] = [AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
                                             AVEncoderAudioQualityKey: AVAudioQuality.max.rawValue,
                                             AVNumberOfChannelsKey: 1,
                                             AVEncoderBitRateKey: 16000,
                                             AVSampleRateKey: 16000]
    

    Also don't forget to change extension in fileName:

    var fileName: String = "audioFile.mp4"