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:
- An enum value:
case decoderTemporarilyUnavailable = -11839
- Link to this error: https://developer.apple.com/reference/avfoundation/averror.code/1388106-decodertemporarilyunavailable
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)
}
}
You should limit
AVPlayer
instances associated withAVPlayerItem
s simultaneously. Just replace player's current item withnil
for players not visible on the screen:Looks like there is no other way to check if resources available else than to try to play and get this error.