How to Record and Play Audio in iPhone using swift 4 - Swift 4 Tutorials W3Schools

Hot

Post Top Ad

27 Nov 2017

How to Record and Play Audio in iPhone using swift 4

In this article we are going to learn about recording sound using Swift 4. Not only recording but also playing the recorded file.

Here we are using AVAudioRecorder for recording audio and AVAudioPlayer for playing the sound.

It's an easy to record using AVAudioRecorder. We will explain step by step how to record an audio.

For testing this we need a device, because simulator don't has microphone.

How to Record and Play Audio in iPhone using swift 4

Getting Started:

Firstly create a new Xcode project and name it as 'VoiceRecorder' and save.

Before getting into code we need to add Microphone usage description in Info.plist.

Open Info.plist and add 'Privacy - Microphone Usage Description' key, othersiwe app will creash.

Next open ViewController.swift file and import the following AVFoundation framework:

import AVFoundation

Next add the following properties to the view controller:

var recordButton = UIButton()
var playButton = UIButton()
var isRecording = false
var audioRecorder: AVAudioRecorder?
var player : AVAudioPlayer?

Record button is to start or stop the recording, play button is to play the recorded sound, isRecoding is an Bool to know the state, audio Recorder is to handle the actual reading and saving of data and finally player to handle the actual playing or stopping the audio.

Microphone Permission:

Next step is we need to ask the user's permission for accessing the microphone in order to stop malicious apps doing malicious things. If the user grant permission we will add the record and play button UI.

Add the following code inside viewDidLoad() method:

view.backgroundColor = UIColor.black

// Asking user permission for accessing Microphone
AVAudioSession.sharedInstance().requestRecordPermission () {
    [unowned self] allowed in
    if allowed {
        // Microphone allowed, do what you like!
        self.setUpUI()
    } else {
        // User denied microphone. Tell them off!
        
    }
}

Add the following methods for setting up the UI:

// Adding play button and record buuton as subviews
func setUpUI() {
    recordButton.translatesAutoresizingMaskIntoConstraints = false
    playButton.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(recordButton)
    view.addSubview(playButton)
    
    // Adding constraints to Record button
    recordButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    recordButton.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
    let recordButtonHeightConstraint = recordButton.heightAnchor.constraint(equalToConstant: 50)
    recordButtonHeightConstraint.isActive = true
    recordButton.widthAnchor.constraint(equalTo: recordButton.heightAnchor, multiplier: 1.0).isActive = true
    recordButton.setImage(#imageLiteral(resourceName: "record"), for: .normal)
    recordButton.layer.cornerRadius = recordButtonHeightConstraint.constant/2
    recordButton.layer.borderColor = UIColor.white.cgColor
    recordButton.layer.borderWidth = 5.0
    recordButton.imageEdgeInsets = UIEdgeInsetsMake(-20, -20, -20, -20)
    recordButton.addTarget(self, action: #selector(record(sender:)), for: .touchUpInside)
    
    // Adding constraints to Play button
    playButton.heightAnchor.constraint(equalToConstant: 60).isActive = true
    playButton.widthAnchor.constraint(equalTo: playButton.heightAnchor, multiplier: 1.0).isActive = true
    playButton.trailingAnchor.constraint(equalTo: recordButton.leadingAnchor, constant: -16).isActive = true
    playButton.centerYAnchor.constraint(equalTo: recordButton.centerYAnchor).isActive = true
    playButton.setImage(#imageLiteral(resourceName: "play"), for: .normal)
    playButton.addTarget(self, action: #selector(play(sender:)), for: .touchUpInside)
}

@objc func record(sender: UIButton) {

}

@objc func play(sender: UIButton) {
    
}

Here we added button using auto layout constraints programmatically.

Build and Run, next allow the Microphone for recording. Then the screen looks like below:

Play and stop button for recording swift 4

Start recording:

All buttons setting up done, next step is to start recording.

Add the following method to record an audio:

func startRecording() {
    //1. create the session
    let session = AVAudioSession.sharedInstance()
    
    do {
        // 2. configure the session for recording and playback
        try session.setCategory(AVAudioSessionCategoryPlayAndRecord, with: .defaultToSpeaker)
        try session.setActive(true)
        // 3. set up a high-quality recording session
        let settings = [
            AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
            AVSampleRateKey: 44100,
            AVNumberOfChannelsKey: 2,
            AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
        ]
        // 4. create the audio recording, and assign ourselves as the delegate
        audioRecorder = try AVAudioRecorder(url: getAudioFileUrl(), settings: settings)
        audioRecorder?.delegate = self
        audioRecorder?.record()
        
        //5. Changing record icon to stop icon
        isRecording = true
        recordButton.setImage(#imageLiteral(resourceName: "stop"), for: .normal)
        recordButton.imageEdgeInsets = UIEdgeInsetsMake(5, 5, 5, 5)
        playButton.isEnabled = false
    }
    catch let error {
        // failed to record!
    }
}

Here we created AVAudioSession and creating audio recording. Add the following method for getting the path to save or retrieve the audio.

// Path for saving/retreiving the audio file
func getAudioFileUrl() -> URL{
    let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
    let docsDirect = paths[0]
    let audioUrl = docsDirect.appendingPathComponent("recording.m4a")
    return audioUrl
}

Next step is to conform to AVAudioRecorderDelegate protocol as follow:

class ViewController: UIViewController, AVAudioRecorderDelegate {

Next add the following code inside record() method:

Stop Recording:

Add the following method to stop recording an audio.

// Stop recording
func finishRecording() {
    audioRecorder?.stop()
    isRecording = false
    recordButton.imageEdgeInsets = UIEdgeInsetsMake(-20, -20, -20, -20)
    recordButton.setImage(#imageLiteral(resourceName: "record"), for: .normal)
}

Just needs to call either startRecording() or finishRecording() depending on the isRecording state.

Next add the following code inside record() method:

if isRecording {
    finishRecording()
}else {
    startRecording()
}

Before you're done, there's one more thing to be aware of: iOS might stop your recording for some reason out of your control, such as if a phone call comes in. We use the delegate of the audio recorder, so if this situation crops up you'll be sent a audioRecorderDidFinishRecording() message that you can pass on to finishRecording() like this:

func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {
    if flag {
        finishRecording()
    }else {
        // Recording interrupted by other reasons like call coming, reached time limit.
    }
    playButton.isEnabled = true
}

That's it recording an audio successfully completed.

Play Audio:

For playing sound we are using AVAudioPlayer, so add the following method:

func playSound(){
    let url = getAudioFileUrl()
    
    do {
        // AVAudioPlayer setting up with the saved file URL
        let sound = try AVAudioPlayer(contentsOf: url)
        self.player = sound
        
        // Here conforming to AVAudioPlayerDelegate
        sound.delegate = self
        sound.prepareToPlay()
        sound.play()
        recordButton.isEnabled = false
    } catch {
        print("error loading file")
        // couldn't load file :(
    }
}

Conform to the AVAudioPlayerDelegate protocol as follow:

class ViewController: UIViewController, AVAudioRecorderDelegate, AVAudioPlayerDelegate {

Next call the following method inside play() method as follow:

@objc func play(sender: UIButton) {
    playSound()
}

Add the AVAudioPlayerDelegate delegate method audioPlayerDidFinishPlaying() as follow to know whether audio finished playing or interrupted by an reason.

func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
    if flag {
        
    }else {
        // Playing interrupted by other reasons like call coming, the sound has not finished playing.
    }
    recordButton.isEnabled = true
}

Great we are done, it's time to run and test.

Download sample project with example :

No comments:

Post a Comment

Post Top Ad