Recording audio in Swift
In Swift 3
- Add framework AVFoundation
- **In info.plist add key value
Key = Privacy - Microphone Usage Description and Value = For using microphone
(the apps will crash if you don't provide the value - description why you are asking for the permission)**
-
Import AVFoundation & AVAudioRecorderDelegate, AVAudioPlayerDelegate
import AVFoundation class RecordVC: UIViewController , AVAudioRecorderDelegate, AVAudioPlayerDelegate
-
Create button for record audio & play audio , and label for display recording timing & give outlets and action as start_recording , play_recording & declare some variables which we will use later
@IBOutlet var recordingTimeLabel: UILabel! @IBOutlet var record_btn_ref: UIButton! @IBOutlet var play_btn_ref: UIButton! var audioRecorder: AVAudioRecorder! var audioPlayer : AVAudioPlayer! var meterTimer:Timer! var isAudioRecordingGranted: Bool! var isRecording = false var isPlaying = false
-
In viewDidLoad check record permission
override func viewDidLoad() { super.viewDidLoad() check_record_permission() } func check_record_permission() { switch AVAudioSession.sharedInstance().recordPermission() { case AVAudioSessionRecordPermission.granted: isAudioRecordingGranted = true break case AVAudioSessionRecordPermission.denied: isAudioRecordingGranted = false break case AVAudioSessionRecordPermission.undetermined: AVAudioSession.sharedInstance().requestRecordPermission({ (allowed) in if allowed { self.isAudioRecordingGranted = true } else { self.isAudioRecordingGranted = false } }) break default: break } }
-
generate path where you want to save that recording as myRecording.m4a
func getDocumentsDirectory() -> URL { let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) let documentsDirectory = paths[0] return documentsDirectory } func getFileUrl() -> URL { let filename = "myRecording.m4a" let filePath = getDocumentsDirectory().appendingPathComponent(filename) return filePath }
-
Setup the recorder
func setup_recorder() { if isAudioRecordingGranted { let session = AVAudioSession.sharedInstance() do { try session.setCategory(AVAudioSessionCategoryPlayAndRecord, with: .defaultToSpeaker) try session.setActive(true) let settings = [ AVFormatIDKey: Int(kAudioFormatMPEG4AAC), AVSampleRateKey: 44100, AVNumberOfChannelsKey: 2, AVEncoderAudioQualityKey:AVAudioQuality.high.rawValue ] audioRecorder = try AVAudioRecorder(url: getFileUrl(), settings: settings) audioRecorder.delegate = self audioRecorder.isMeteringEnabled = true audioRecorder.prepareToRecord() } catch let error { display_alert(msg_title: "Error", msg_desc: error.localizedDescription, action_title: "OK") } } else { display_alert(msg_title: "Error", msg_desc: "Don't have access to use your microphone.", action_title: "OK") } }
-
Start recording when button start_recording press & display seconds using updateAudioMeter, & if recording is start then finish the recording
@IBAction func start_recording(_ sender: UIButton) { if(isRecording) { finishAudioRecording(success: true) record_btn_ref.setTitle("Record", for: .normal) play_btn_ref.isEnabled = true isRecording = false } else { setup_recorder() audioRecorder.record() meterTimer = Timer.scheduledTimer(timeInterval: 0.1, target:self, selector:#selector(self.updateAudioMeter(timer:)), userInfo:nil, repeats:true) record_btn_ref.setTitle("Stop", for: .normal) play_btn_ref.isEnabled = false isRecording = true } } func updateAudioMeter(timer: Timer) { if audioRecorder.isRecording { let hr = Int((audioRecorder.currentTime / 60) / 60) let min = Int(audioRecorder.currentTime / 60) let sec = Int(audioRecorder.currentTime.truncatingRemainder(dividingBy: 60)) let totalTimeString = String(format: "%02d:%02d:%02d", hr, min, sec) recordingTimeLabel.text = totalTimeString audioRecorder.updateMeters() } } func finishAudioRecording(success: Bool) { if success { audioRecorder.stop() audioRecorder = nil meterTimer.invalidate() print("recorded successfully.") } else { display_alert(msg_title: "Error", msg_desc: "Recording failed.", action_title: "OK") } }
-
Play the recording
func prepare_play() { do { audioPlayer = try AVAudioPlayer(contentsOf: getFileUrl()) audioPlayer.delegate = self audioPlayer.prepareToPlay() } catch{ print("Error") } } @IBAction func play_recording(_ sender: Any) { if(isPlaying) { audioPlayer.stop() record_btn_ref.isEnabled = true play_btn_ref.setTitle("Play", for: .normal) isPlaying = false } else { if FileManager.default.fileExists(atPath: getFileUrl().path) { record_btn_ref.isEnabled = false play_btn_ref.setTitle("pause", for: .normal) prepare_play() audioPlayer.play() isPlaying = true } else { display_alert(msg_title: "Error", msg_desc: "Audio file is missing.", action_title: "OK") } } }
-
When recording is finish enable the play button & when play is finish enable the record button
func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) { if !flag { finishAudioRecording(success: false) } play_btn_ref.isEnabled = true } func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) { record_btn_ref.isEnabled = true }
-
Generalize function for display alert
func display_alert(msg_title : String , msg_desc : String ,action_title : String) { let ac = UIAlertController(title: msg_title, message: msg_desc, preferredStyle: .alert) ac.addAction(UIAlertAction(title: action_title, style: .default) { (result : UIAlertAction) -> Void in _ = self.navigationController?.popViewController(animated: true) }) present(ac, animated: true) }
Here is code.You can record easily.Write this code on IBAction
.It will save the recording in Documents
by name recordTest.caf
//declare instance variable
var audioRecorder:AVAudioRecorder!
func record(){
var audioSession:AVAudioSession = AVAudioSession.sharedInstance()
audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord, error: nil)
audioSession.setActive(true, error: nil)
var documents: AnyObject = NSSearchPathForDirectoriesInDomains( NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0]
var str = documents.stringByAppendingPathComponent("recordTest.caf")
var url = NSURL.fileURLWithPath(str as String)
var recordSettings = [AVFormatIDKey:kAudioFormatAppleIMA4,
AVSampleRateKey:44100.0,
AVNumberOfChannelsKey:2,AVEncoderBitRateKey:12800,
AVLinearPCMBitDepthKey:16,
AVEncoderAudioQualityKey:AVAudioQuality.Max.rawValue]
println("url : \(url)")
var error: NSError?
audioRecorder = AVAudioRecorder(URL:url, settings: recordSettings, error: &error)
if let e = error {
println(e.localizedDescription)
} else {
audioRecorder.record()
}
}
Swift2 version of @codester's answer.
func record() {
//init
let audioSession:AVAudioSession = AVAudioSession.sharedInstance()
//ask for permission
if (audioSession.respondsToSelector("requestRecordPermission:")) {
AVAudioSession.sharedInstance().requestRecordPermission({(granted: Bool)-> Void in
if granted {
print("granted")
//set category and activate recorder session
try! audioSession.setCategory(AVAudioSessionCategoryPlayAndRecord)
try! audioSession.setActive(true)
//get documnets directory
let documentsDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]
let fullPath = documentsDirectory.stringByAppendingPathComponent("voiceRecording.caf")
let url = NSURL.fileURLWithPath(fullPath)
//create AnyObject of settings
let settings: [String : AnyObject] = [
AVFormatIDKey:Int(kAudioFormatAppleIMA4), //Int required in Swift2
AVSampleRateKey:44100.0,
AVNumberOfChannelsKey:2,
AVEncoderBitRateKey:12800,
AVLinearPCMBitDepthKey:16,
AVEncoderAudioQualityKey:AVAudioQuality.Max.rawValue
]
//record
try! self.audioRecorder = AVAudioRecorder(URL: url, settings: settings)
} else{
print("not granted")
}
})
}
}