AVPlayerViewController using audio-only AVPlayer

i0S Swift Issue

Question or problem in the Swift programming language:

Just starting out with AVKit, and I’m trying to play some audio. It would be nice to use the new AVPlayerViewController detailed in Mastering Modern Media Playback so that I have a ready-made play/pause/seek UI. I basically have a storyboard with a container view which has an embed segue to the AVPlayerViewController. Then I use:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if (segue.identifier == "embedAudio") {
        var playerViewController:AVPlayerViewController = segue.destinationViewController as AVPlayerViewController

        playerViewController.player = AVPlayer(URL: NSURL(string: "http://dts.podtrac.com/redirect.mp3/files.serialpodcast.org/sites/default/files/podcast/1420057326/serial-s01-e01.mp3"))
    }
}

It embeds nicely and plays, but it has a big black QuickTime symbol where the video would be. I’m wondering if there’s a way to make it look more like the Music or Podcasts app.

How to solve the problem:

Solution 1:

Why reinvent the wheel? Just use AVPlayerViewController‘s contentOverlayView property. Here you can set an album artwork image, or place any UIView between the QuickTime logo (where the video would be), and the controls.

Note that you must do this after the AVPlayerViewController has been presented, as its contentOverlayView property will be nil in prepareForSegue

Solution 2:

Do not use the AVPlayerViewController, as it is a full screen, black box, video player.

Instead, create your own view controller with, say, a toolbar and controls readily available in the OS (play, pause, stop, etc.) and hook them to your AVAudioPlayer. This is what the code of your very own view controller may look like:

Maintain an instance of the player

var audioPlayer:AVAudioPlayer!
@IBOutlet weak var playProgress: UIProgressView!

Example: Play

@IBAction func doPlayAction(_ sender: AnyObject) {
    do {
        try audioPlayer = AVAudioPlayer(contentsOf: audioRecorder.url)
        audioPlayer.play()
    } catch {}
}

Example: Stop

@IBAction func doStopAction(_ sender: AnyObject) {
    if let audioPlayer = self.audioPlayer {
        audioPlayer.stop()
    }
}

Example: Track progress

func playerProgress() {
    var progress = Float(0)
    if let audioPlayer = audioPlayer {
        progress = ((audioPlayer.duration > 0)
            ? Float(audioPlayer.currentTime/audioPlayer.duration)
            : 0)
    }
    playProgress.setProgress(progress, animated: true)
}

I have posted a recording and playback example using the methodology outlined in this answer.

Preview

► Find this solution on GitHub.

Hope this helps!