In this tutorial, we are going to see the required steps to record and play sound in Swift Programming language using AVAudioRecorder and AVAudioPlayer
Download source code from github (SoundController.swift)
User Interface
The user interface for this demo is simple with two buttons, one for recording and another for playing sound.
Create corresponding IBAction and IBOutlets from the two button in the View Controller.
@IBOutlet weak var recordButton: UIButton!
@IBOutlet weak var playButton: UIButton!
@IBAction func recordSound(sender: UIButton)
@IBAction func playSound(sender: UIButton)
Dual Purpose Buttons
The Record button will be used to record and stop recording. Similarly the Play button will used to Play and Stop the audio.
Class level var and let declaration
var soundRecorder: AVAudioRecorder!
var soundPlayer:AVAudioPlayer!
let fileName = “demo.caf”
Declare two class level variable for holding an instance of AVAudioRecorder and AvAudioPlayer. Also create constant for holding the file name.
Create Sound file path
For this demo, the sound file will be created under the Cache directory using the name defined in the constant. Add these two function to your class
func getCacheDirectory() -> String {
let paths = NSSearchPathForDirectoriesInDomains(.CachesDirectory,.UserDomainMask, true) as [String]
return paths[0]
}
func getFileURL() -> NSURL {
let path = getCacheDirectory().stringByAppendingPathComponent(fileName)
let filePath = NSURL(fileURLWithPath: path)
return filePath!
}
The getCacheDirectory retrieves the caches directory and getFileURL appends the file name with the cache directory.
Setup Recorder
Create a new function that prepares the recorder and this function will be called during the viewDidLoad operation
func setupRecorder() {
//set the settings for recorder
var recordSettings = [
AVFormatIDKey: kAudioFormatAppleLossless,
AVEncoderAudioQualityKey : AVAudioQuality.Max.rawValue,
AVEncoderBitRateKey : 320000,
AVNumberOfChannelsKey: 2,
AVSampleRateKey : 44100.0
]
var error: NSError?
soundRecorder = AVAudioRecorder(URL: getFileURL(), settings: recordSettings, error: &error)
if let err = error {
println(“AVAudioRecorder error: \(err.localizedDescription)“)
} else {
soundRecorder.delegate = self
soundRecorder.prepareToRecord()
}
}
To create an AVAudioRecorder instance, you need to pass three parameters,
URL– Specifies the path and name of the file where the sound will be recorded.
settings – Configure AVRecorder settings
error – Capture error while creating AVRecorder instance.
If there is no error while creating Audio Recorder, the delegate it set to the View Controller and recorder is prepared for recording. Make sure the View Controller conforms to AVAudioRecorderDelegate
class SoundController: UIViewController, AVAudioRecorderDelegate {
Prepare Player
Add the following function that prepares the AVAudiPlayer to play the recorded sound
func preparePlayer() {
var error: NSError?
soundPlayer = AVAudioPlayer(contentsOfURL: getFileURL(), error: &error)
if let err = error {
println(“AVAudioPlayer error: \(err.localizedDescription)“)
} else {
soundPlayer.delegate = self
soundPlayer.prepareToPlay()
soundPlayer.volume = 1.0
}
}
AVAudioPlayer instance is created by passing sound file that needs to be played along with pointer to capture errors while creating AVAudioPlayer instance. Make sure the View Controller conforms to AVAudioPlayerDelegate. Then call the prepareToPlay function on the AVAudioPlayer instance.
Implement IBActions function to record and play sound
Add the following implementation to the IBAction functions which records and plays sound.
@IBAction func recordSound(sender: UIButton) {
if (sender.titleLabel?.text == “Record”){
soundRecorder.record()
sender.setTitle(“Stop”, forState: .Normal)
playButton.enabled = false
} else {
soundRecorder.stop()
sender.setTitle(“Record”, forState: .Normal)
}
}
@IBAction func playSound(sender: UIButton) {
if (sender.titleLabel?.text == “Play”){
recordButton.enabled = false
sender.setTitle(“Stop”, forState: .Normal)
preparePlayer()
soundPlayer.play()
} else {
soundPlayer.stop()
sender.setTitle(“Play”, forState: .Normal)
}
}
When the Record button is tapped, the name of the button is changed to Stop and starts recording the sound. Similarly when the title is Stop, the recording the stopped and play button is enabled. The same is done when the user taps the play button.
class SoundController: UIViewController, AVAudioRecorderDelegate, AVAudioPlayerDelegate {
Implement AVAudioRecorderDelegate methods
func audioRecorderDidFinishRecording(recorder: AVAudioRecorder!, successfully flag: Bool) {
playButton.enabled = true
recordButton.setTitle(“Record”, forState: .Normal)
}
func audioRecorderEncodeErrorDidOccur(recorder: AVAudioRecorder!, error: NSError!) {
println(“Error while recording audio \(error.localizedDescription)“)
}
Implement AVAudioPlayerDelegate methods
func audioPlayerDidFinishPlaying(player: AVAudioPlayer!, successfully flag: Bool) {
recordButton.enabled = true
playButton.setTitle(“Play”, forState: .Normal)
}
func audioPlayerDecodeErrorDidOccur(player: AVAudioPlayer!, error: NSError!) {
println(“Error while playing audio \(error.localizedDescription)“)
}
Now you are good to go and try this demo. You can download the source code for recording and playing audio in swift from github.
Thank you so much for this tutorial. It’s very helfull to an absolute beginner like me. However, I an looking to program an even simpler app. I need it to have two buttons. One that records and another one that plays back without saving to a file. I want to press record; not pause or save but rather, press the play button and have the app play back the reasent recording. Press record again; have the previous recording purged and so on. Record – play, record – play and so on and on.
I think this is a stripped down version of your demo app, but, being a total novice, I don’t know what parts of your code need to be stripped or modified. Can you help please?
Hi Joaquin,
That is exactly what the code does. Record -> saves to cache / Play -> reads from cache.
Hit Record again -> overwrites cache / Play -> reads from new cache.
So good news, no stripping needed! Just try it!
Cheers
Hi love this website! can you convert the program to swift 2 as its throwing up errors i don’t understand
The project has been updated for Swift 2.0, Could you please try now. – https://github.com/rshankras/SwiftDemo
Hey Ravi, thank you for posting up your tutorial, I love how it has the bare bones so I can see exactly what we’re working on. However, I seem to be having some problems with this line of code:
soundRecorder = AVAudioRecorder(URL: getFileURL(), settings: recordSettings as [NSObject : AnyObject], error: &error)
“Xcode is telling me that “cannot capture “getfileurl” before it is declared”
I was wondering if you had any suggestion in order to move forward?
Thanks!
Thanks. I have made some changes for Swift 2.0 (Xcode 7.0), could you please take the latest from gitHub (https://github.com/rshankras/SwiftDemo). The problematic line is now changed to
soundRecorder = try AVAudioRecorder(URL: getFileURL(), settings: recordSettings)
Hi rshankar,
your project only works on simulator, don’t work on devices. I have tested this examples and didn’t work. I think the problem is in the cache path. Do you have a solution ?
Thank you ver Much providing this tutorial
Why don’t hear music after recording while headphone is plugged in? What is the solution to record audio in headphone plugged in and out?
The post is really in depth and step by step unlike a lot of other ones I have read so far. I just hope you write a new one for Swift 5. This program doesn’t run anymore on the latest Xcode 10 and Swift 5