Check when resources are available from AVFoundation

2k views Asked by At

I'm using AVFoundation and creating AVPlayer's but getting some errors as shown below.

These are the 2 errors:

2017-01-06 15:51:19.974693 DemoApp[11855:3855225] Video player Status Failed: player item error = Error Domain=AVFoundationErrorDomain Code=-11839 "Cannot Decode" UserInfo={NSUnderlyingError=0x174253ef0 {Error Domain=NSOSStatusErrorDomain Code=-12913 "(null)"}, NSLocalizedFailureReason=The decoder required for this media is busy., NSLocalizedRecoverySuggestion=Stop any other actions that decode media and try again., NSLocalizedDescription=Cannot Decode}

2017-01-06 15:51:19.974783 DemoApp[11855:3855225] Video player Status Failed: player error = (null)

I'm able to print these 2 errors like so:

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {
    ///.. other code ..///

      case AVPlayerItemStatusFailed: {
        print("Video player Status Failed: player item error = \(self.player.currentItem.error)")
        print("Video player Status Failed: player error = \(self.player.error)")
    } 
}

Apple's documentation for this error:

It seems Apple has a limit to how many AVPlayer's the entire system could create; which means all apps share these resources. I want to check for this so that I could respond appropriately in my app.

Is there a way to check when these resources are available? Like when is the decoder available?

Update 1

Below is snippet of what I'm doing. On an iPhone 6s, there seems to be a limit of 16 AVPlayer's that can be created and played simultaneously. In this app, the function below called refreshVideoPlayersAndTable creates 10 AVPlayer's every time the app launches and starts playing all of them. When the app goes to background, I release these shared resources by deleting and removing all video players.

Note: This error occurs mostly if I use another app that plays many videos simultaneously and is therefore using the shared resources from iOS. There aren't too many apps that use 10 or more AVPlayer's at once but there are a couple. When I use another app that does so and then switch to my app right away, then I need to put the delay like below to avoid any decode error's.

My main goal is to check for when the resources are available instead of using an arbitrary delay in order to create the video players.

class MyViewController: UIViewController {

    override func viewDidLoad() {
            super.viewDidLoad()

        registerNotifications()
    }

    func applicationWillEnterForeground(notification: Notification) {

        /// Hack: Without a delay, it seems that iOS does not have the resources
        /// available to refresh the AVPlayer's. We get `decode errors` if we
        /// instantiate them without a delay.
        delay(1) { [weak self] in
          self?.refreshVideoPlayersAndTable()
        }
    }

    func applicationDidEnterBackground(notification: Notification) {
      /// Release shared resources - delete and remove all AVPlayer's
        removeAllVideoPlayers()
    }

    func registerNotifications() {
        NotificationCenter.default.addObserver(self, selector: #selector(MyViewController.applicationDidEnterBackground), name: .UIApplicationDidEnterBackground, object: nil)
            NotificationCenter.default.addObserver(self, selector: #selector(MyViewController.applicationWillEnterForeground), name: .UIApplicationWillEnterForeground, object: nil)
    }
}
1

There are 1 answers

2
k06a On

You should limit AVPlayer instances associated with AVPlayerItems simultaneously. Just replace player's current item with nil for players not visible on the screen:

player.replaceCurrentItemWithPlayerItem(nil)

Looks like there is no other way to check if resources available else than to try to play and get this error.