Implementing basic audio controls

Before you implement the audio player code, you will need to do a little bit of housekeeping. To be able to play audio, you need a list of the files that the player will play. In addition to this list, you also need to keep track of what song the user is currently playing, so you can determine the next and previous songs. Lastly, you also need to have the audio player itself. Instead of using a pre-built component, you will build your own audio player using an AVAudioPlayer object. The AVAudioPlayer is perfect for implementing a simple audio player that plays a couple of local .mp3 files. It offers some convenient helper methods to easily adjust the player's volume, seek to a specific timestamp in the song, and more.

Define the following properties in AudioViewController.swift:

let files = ["one", "two", "three"]
var currentTrack = 0
var audioPlayer: AVAudioPlayer!

Make sure to replace the files array with the filenames that you use for your own audio files. The audioPlayer does not have a value yet at this point. You will set up the audio player next.

Before you can play audio, you need to obtain a reference to a media file and provide this reference to an AVAudioPlayer object. Any time you want to load a new media file, you will have to create a new instance of the audio player, since you can't change the current file once a file is playing. Add the following helper method to the AudioViewController to load the current track and create an AVAudioPlayer instance:

func loadTrack() {
  let url = Bundle.main.url(forResource: files[currentTrack], withExtension: "mp3")!
  audioPlayer = try! AVAudioPlayer(contentsOf: url)
  audioPlayer.delegate = self
}

This method reads the file name for the current track and retrieves the local URL for it. This URL is then used to create and set the audioPlayer property on the AudioViewController. The view controller is also assigned as the delegate for the audio player. You won't implement any of the delegate methods just yet, but you can add the following extension to make AudioViewController conform to the AVAudioPlayerDelegate protocol to ensure your code compiles:

extension AudioViewController: AVAudioPlayerDelegate {

}

You will implement one of the AVAudioPlayerDelegate methods when you add support for navigating to the next and previous tracks.

Add the following two methods to the audio view controller to add support for playing and pausing the current audio file:

func startPlayback() {
  audioPlayer.play()
  playPause.setTitle("Pause", for: .normal)
}

func pausePlayback() {
  audioPlayer.pause()
  playPause.setTitle("Play", for: .normal)
}

These methods are relatively straightforward. They call the audio player's play() and pause() methods and update the button's label, so it reflects the current player state. Add the following implementation for playPauseTapped() so the play and pause methods get called when the user taps the play/pause button:

@IBAction func playPauseTapped() {
  if audioPlayer.isPlaying {
    pausePlayback()
  } else {
    startPlayback()
  }
}

If you run the app now, you can tap the play/pause button to start and stop the currently playing file. Make sure your device is not in silent mode, because the audio for your app is muted when the device is in silent mode. You will learn how to fix this when you implement the ability to play audio in the background. The next step is to add support for playing the next and previous tracks. Add the following two implementations to AudioViewController to do this:

@IBAction func nextTapped() {
  currentTrack += 1
  if currentTrack >= files.count {
    currentTrack = 0
  }
  loadTrack()
  audioPlayer.play()
}

@IBAction func previousTapped() {
  currentTrack -= 1
  if currentTrack < 0 {
    currentTrack = files.count - 1
  }
  loadTrack()
  audioPlayer.play()
}

The preceding code adjusts the current track index, loads the new track, and immediately plays it. Note that every time the user taps on the next or previous button, a fresh audio player has to be created by calling loadTrack(). If you run the app now, you can play audio, pause it, and skip to the next or previous tracks.

When you allow a full song to play, it won't yet advance to the next song afterward. To implement this, you need to add an implementation for the audioPlayerDidFinishPlaying(_:successfully:) method from AVAudioPlayerDelegate. Add the following implementation to call nextTapped(), so the next song automatically plays when the current song finishes:

func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
  nextTapped()
}

Now that the first features are implemented, the next step is to implement the time scrubber that shows the current song's progress and allows the user to adjust the playhead's position.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.173.227