0

I have an app where users can play videos fullscreen. This is accomplished quite simply with AVPlayerViewController.

It works great, but in circumstances where the user is, say, listening to a podcast, if they tap on a video to watch it'll pause the podcast so that the user can watch the video, but when I close the video I would expect the podcast to resume. This is the behavior in most apps, I've confirmed it with Twitter and Tweetbot, for instance. Weirdly, the below code works for Apple Podcasts (it will resume), but no others, and other apps like the aforementioned Tweetbot work universally.

I've had absolutely no luck getting this to work myself however.

Things I've tried:

  • Just presenting the AVPlayerViewController with the minimum amount of code required: doesn't resume.
  • On viewDidDisappear of the AVPlayerViewController calling AVAudioSession.sharedInstance().setActive(false, options: .notifyOthersOnDeactivation): doesn't resume and spits out a "player is busy" error.
  • Okay, let's try stopping the player manually with player?.pause() in viewDidDisappear: doesn't resume, still gives a "player is busy" error.
  • Hmm, maybe give it a second? Try calling setActive after a DispatchQueue.main.asyncAfter of 1 second? No error, but doesn't resume.

I've put it in a test project with a very minimal amount of code:

import UIKit
import AVKit
import AVFoundation

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        let button = UIButton(type: .system)
        button.addTarget(self, action: #selector(buttoned(sender:)), for: .touchUpInside)
        button.setTitle("Tap here to view video", for: .normal)
        button.titleLabel?.font = UIFont.systemFont(ofSize: 19.0)
        button.frame = view.bounds
        view.addSubview(button)
    }

    @objc private func buttoned(sender: UIButton) {
        let videoURL = URL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
        let player = AVPlayer(url: videoURL!)
        let playerViewController = CustomVideoController()
        playerViewController.player = player
        self.present(playerViewController, animated: true) {
            playerViewController.player?.play()
        }
    }
}

class CustomVideoController: AVPlayerViewController {
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)

        do {
            try AVAudioSession.sharedInstance().setActive(false, options: .notifyOthersOnDeactivation)
        } catch {
            print(error)
        }
    }
}

Here's the complete compile-able project (literally just the above code): https://drive.google.com/file/d/1oWb-bNIQv5B1KjMkez6BxuEIh_n6eFxH/view

Play something from like Apple Music, Spotify, Overcast, etc. then run the app and tap view video.

I'm kinda going crazy trying to figure this relatively trivial thing out, as I'm sure I'm just doing something incredibly stupid, but any help would be appreciated.

christianselig
  • 405
  • 4
  • 17

2 Answers2

0

Have you tried to use player as member var? So you can destroy it after view is disappeared, haven't tested yet, but the code should be like this:

import UIKit
import AVKit
import AVFoundation

class ViewController: UIViewController {

    var player:AVPlayer?

    override func viewDidLoad() {
        super.viewDidLoad()

        let button = UIButton(type: .system)
        button.addTarget(self, action: #selector(buttoned(sender:)), for: .touchUpInside)
        button.setTitle("Tap here to view video", for: .normal)
        button.titleLabel?.font = UIFont.systemFont(ofSize: 19.0)
        button.frame = view.bounds
        view.addSubview(button)
    }

    @objc private func buttoned(sender: UIButton) {
        let videoURL = URL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
        player = AVPlayer(url: videoURL!)
        let playerViewController = CustomVideoController()
        playerViewController.player = player
        self.present(playerViewController, animated: true) {
            playerViewController.player?.play()
        }
    }
}

class CustomVideoController: AVPlayerViewController {
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        player.pause()
        player = nil
        do {
            try AVAudioSession.sharedInstance().setActive(false, options: .notifyOthersOnDeactivation)
        } catch {
            print(error)
        }
    }
}
thachnb
  • 1,503
  • 10
  • 13
0

(Sorry, I cannot seem to leave comments)

Have you tried testing on a different device (with different iOS version?). Your sample code worked fine on my iPhone 6 (iOS 12.1.2), I tested both Music and Podcasts.

Bill
  • 469
  • 2
  • 4
  • Apple-made apps do seem to work, but I can't find any third party apps that do work. Try any other app that plays background audio. – christianselig Jan 31 '19 at 17:16