Record and Play Audio Part 3/3

Welcome reader to the final part of the Record and Play Audio tutorial.

Tutorial Revision Notes
  • The tutorial was updated to fixed the issue of the AudioDiary app not working on a real device.
  • Code presented on this page assume you are using Xcode 7.1 and Swift version 2. So if you are using a newer version of Swift, it may produce errors. Fix them by using Xcode’s Fix-it tool.
  • I assume you aren’t a newbie to the Swift Programming Language and you know your way around Xcode Integrated Development Editor.
  • Icons used in the Xcode project was downloaded for free on the icons8 site.

I refer to the Simulator and your real device as “your device”. If you have a “real device”, you should use it to test code presented in this post. If not, then use the Simulator.

audiodiary-screen7bThe Player View is shown when the app user tap the Recordings View’s table view cell. You’ll add code in the PlayerViewController.swift class file to enable the app user to perform these tasks:

  • Play the selected sound file
  • Pause the sound file that’s playing
  • Stop playback of the sound file

You will create an object called, audioPlayer from the AVAudioPlayer class. You will use the object’s functions to perform above tasks.

The Navigation Bar Button

When the app user tap the navigation bar button, the app will segue him back to the Recordings View.

The NSTimer Class

An instance of the NSTimer class will animate the ticker that’s displayed on the playedTime label. The label is located between the Play/Pause button and the Stop button.

The View’s Labels

While the invisible audio player plays a sound file, the app display on a label the the selected sound file’s name. On another playedTime label, the app display the animated ticker. In other words, the label display remaining time of the sound file that’s playing.

The Play/Pause Button

This button display a play and pause icon. When the button is tapped, the app pause or play the selected sound file.

The Stop Button

This button display an icon of a solid blue square. When tapped, it stop playback of the sound file.

The Audio Player View Controller Code

You are ready to add code in the PlayerViewController.swift class file. Start by using the Source Control menu to create a new branch from the “branch-two” branch. Give the new branch the name “branch-three”

Now, modify the top portion of the file to look like this:

audiodiary-code2

The first thing you did is imported the AVFoundation module in the class file. Next, you conformed the PlayerViewController class to the AVAudioPlayerDelegate protocol. Finally, you declared a global object variable called audioPlayer. The AVAudioPlayer class was used as its type. In other words, you created an invisible audioPlayer object from the AVAudioPlayer class.

Now, modify the remain code in the PlayerViewController class file to look like this:

override func viewDidLoad() {
  super.viewDidLoad()
        
  trackTitle.text = selectedAudioFileName
  let fileManager = NSFileManager.defaultManager()
  let urls = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
  let documentsDirectoryURL: NSURL = urls.first!
  fileURL = documentsDirectoryURL.URLByAppendingPathComponent(selectedAudioFileName)
        
  do {
    audioPlayer = try AVAudioPlayer(contentsOfURL: fileURL)
    audioPlayer.prepareToPlay()
    audioPlayer.delegate = self
            
    /*** DEBUG STATEMENT ***/
    print("The audioPlayer is initialized with this URL:\n\(fileURL)")
            
    } catch let error as NSError {
      print("AUDIO PLAYER ERROR\n\(error.localizedDescription)")
    }
  }

  override func viewWillDisappear(animated: Bool) {
    if audioPlayer.playing {
      audioPlayer.stop() // Stop the sound that's playing
    }
  }
    
  override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
  }
    
  @IBAction func playPauseButtonTapped(sender: AnyObject) {
    if audioPlayer.playing {
      audioPlayer.pause()
    } else {
      audioPlayer.play()
      timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "updatePlayedTime", userInfo: nil, repeats: true)
    }
  }
    
  @IBAction func stopButtonTapped(sender: AnyObject) {
    audioPlayer.currentTime = 0
    audioPlayer.stop()
  }
    
  func updatePlayedTime() {
    let currentTime = Int(audioPlayer.currentTime)
    let minutes = currentTime/60
    let seconds = currentTime - minutes * 60
    playedTime.text = NSString(format: "%02d:%02d", minutes, seconds) as String
  }

  func audioPlayerDidFinishPlaying(player: AVAudioPlayer, successfully flag: Bool) {
    let msg = "Your recording was saved as, \(selectedAudioFileName)"
    let alert = UIAlertController(title: "Audio Diary", message: msg, preferredStyle: .Alert)
    alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
    self.presentViewController(alert, animated: true, completion: nil)
  }
    
  func audioPlayerDecodeErrorDidOccur(player: AVAudioPlayer, error: NSError?) {
    let alert = UIAlertController(title: "Audio Diary", message: "Decoding Error: \(error?.localizedDescription)", preferredStyle: .Alert)
    alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
    self.presentViewController(alert, animated: true, completion: nil)
  }
}

Test The Player View Controller Code

Now, run the app on your device and test the code you entered in the PlayerViewController.swift file. You’ll have to click a cell in the Recordings table view to access the Player View.

audiodiary-screen6b

Next, use the Player View’s Play/Pause button to play or pause the selected sound file. Use the Stop button (blue square) to stop playback of a the sound file. Notice how the playTime label’s counter increments as the sound file is playing. It it is reset to 0:00 when the sound file finish playing and when you tap the Stop button.

How The Player View Controller Code Works

It is time to go over how the PlayerViewController.swift file’s code. Let us start the with viewDidLoad() function’s code.

The viewDidLoad Function Code

Code in the viewDidLoad() function:

  • Assign the selected audio file’s name to the trackTitle label.
  • Get the full path to the selected audio file as a URL.
  • Initialize the invisible audioPlayer object with the selected audio file.
  • Prepare the audioPlayer object to play the selected audio file.
  • Make the audioPlayer a delegate of the PlayerViewController class.
  • The first print statement is only for debugging purpose. It print the audio fileURL in the console
  • The second print statement is required. It print in the console, the error message the audioPlayer object return.

Remember, the audio file name was passed to the PlayerViewController class via code you entered in the AudioRecorderViewController.swift file’s prepareForSegue() function.

The viewWillDisappear Function Code

Now, when you tap the Player View’s navigation bar button, the viewWillDisappear() function is fired before you’re transported back to the Recordings View. Code you you entered in the function check to see if the audioPlayer is playing the selected audio file. If it is; the statement in the if block stop the audio sound file. Now, code you entered in the viewWillDisappear() function is very important. It prevent the app from playing multiple sound files at simultaneously. Test this by doing the following:

  • Comment out the ViewDidDisappear() function’s code and run the app on your device.
  • Select an audio file from the Recordings View and tap the Play/Pause button.
  • Tap the Player View’s navigation bar’s button to return to the Recordings View and select another audio file and tap the Play/Pause button to play that sound file.

The app plays both audio files simultaneously. Before proceeding, uncomment the viewWillDisappear() function’s code.

The Play/Pause Button Code

When you tap the Play/Pause button, the playPauseButtonTapped() function is fired. Code you entered in the function pause or play the selected audio file.

The Stop Button Code

When you click the Stop button, the stopButtonTapped() function is fired. Code you entered in the function does set the currentTime variable to 0, and stop playback of the selected audio file.

The updatePlayedTime Function Code

This function pretty much update the playedTime label’s text property by displaying a minutes and seconds ticker. This is done while an audio player is playing. By the way, the updatePlayedTime() function is called in the playPauseButtonTapped() function.

The AVAudioPlayerDelegate Protocol Functions

The final set of code you entered in the PlayerViewController.swift file implemented two delegate functions of the AVAudioPlayerDelegate protocol.

audioPlayerDidFinishPlaying() – This function is fired when the audioPlayer finish playing the sound file. You entered code in the function to inform the user that the sound file finished playing; via an alert view.

audioplayer-figure03b

audioPlayerDecodeErrorDidOccur() – This function is called when an audio player encounters a decoding error during playback of the selected audio file. The alert view code display the decoding error.

The End!

That’s it, you’ve reach the end of the three-part tutorial, Record and Play Audio. Use the Source Control menu to commit changes to the git repository. Here’s the final version of the AudioDiary project.

AudioDiary2-final

Comments are welcomed! 🙂

  • Adarsa Hebbar

    iam using php as server sided programing language
    and swift for client
    in my project i wish to record and upload audio file to the server
    i am using XAMPP server.
    recording part is working good

    but i dont know how to upload audio file to the server

  • Adarsa Hebbar

    Mam how to upload audio file to php server ? i am using swift 1.3 and xcode 6.3.2

  • nuryarisi

    i want to make an app. and i use your Is-Headphone-Plugged-In. it is very good example. Now i am recording my voice with music playing in the background.(like karaoke). my question is how can i hear my voice from headphone? i dont hear my voice from headphone when recording

  • nuryarisi

    will you help me 🙁

  • nuryarisi

    nuryarisi@gmail.com send me please.

    • Here is the link to the final version of the AudioDiary project. It was updated using Xcode 6.4 and Swift 2. Please let me know if this help or not.

      AudioDiary Xcode project

      • nuryarisi

        ohhh you are perfect… 🙂 its work. Can I ask you one more thing ? i am using “https://github.com/gilesvangruisen/Swift-YouTube-Player …” for play youtube videos but in webview ios play red icon shows always..
        Is the sample code I can play YouTube videos and playerparameters can easily change ?.

        • nuryarisi, you are right and I have absolutely no idea why the AudioDiary app isn’t working on a real device. If I figure out the reason, I will let you know.

          • nuryarisi

            applady its working now. thank you very much. it is my fault..:) now everything is ok. thank you.

          • Chris

            What was it, because it crashes for me too, but not in simulator

      • nuryarisi

        DocumentsDirPath:

        /var/mobile/Containers/Data/Application/54EC2810-A61D-4E99-85F0-E425997B4AF4/Documents

        fatal error: unexpectedly found nil while unwrapping an Optional value

  • nuryarisi

    i have get error…playerviewcontroller.swift slider.maximumValue = Float(audioPlayer!.duration) please send me full source code.