iosavplayeravqueueplayer

AVURLAsset loadValuesAsynchronously never fail


I am reading & trying Apple's sample code about loading video assets.

But I notice that the loadValuesAsynchronously function on AVURLAsset never fail even if I turn on airplane mode on the device or turn off wifi on my mac. Anybody know under what situation loadValuesAsynchronously will fail to load the keys?

This is the relative sample code:

asset.loadValuesAsynchronously(forKeys: PlayerViewController.assetKeysRequiredToPlay) {

    /*
        The asset invokes its completion handler on an arbitrary queue.
        To avoid multiple threads using our internal state at the same time
        we'll elect to use the main thread at all times, let's dispatch
        our handler to the main queue.
    */
    DispatchQueue.main.async() {
        /*
            This method is called when the `AVAsset` for our URL has 
            completed the loading of the values of the specified array 
            of keys.
        */

        /*
            Test whether the values of each of the keys we need have been
            successfully loaded.
        */
        for key in PlayerViewController.assetKeysRequiredToPlay {
            var error: NSError?

            if asset.statusOfValue(forKey: key, error: &error) == .failed {
                let stringFormat = NSLocalizedString("error.asset_%@_key_%@_failed.description", comment: "Can't use this AVAsset because one of it's keys failed to load")

                let message = String.localizedStringWithFormat(stringFormat, title, key)

                self.handleError(with: message, error: error)

                return
            }
        }

        // We can't play this asset.
        if !asset.isPlayable || asset.hasProtectedContent {
            let stringFormat = NSLocalizedString("error.asset_%@_not_playable.description", comment: "Can't use this AVAsset because it isn't playable or has protected content")

            let message = String.localizedStringWithFormat(stringFormat, title)

            self.handleError(with: message)

            return
        }

        /*
            We can play this asset. Create a new AVPlayerItem and make it
            our player's current item.
        */
        self.loadedAssets[title] = asset

        let name = (thumbnailResourceName as NSString).deletingPathExtension
        let type = (thumbnailResourceName as NSString).pathExtension
        let path = Bundle.main.path(forResource: name, ofType: type)!

        let thumbnail = UIImage(contentsOfFile: path)!

        self.assetTitlesAndThumbnails[asset.url] = (title, thumbnail)
    }
}

Solution

  • Finally figured this out, to answer my own question: I've been using HLS videos and the URL is of the format https://www.foo.com/master.m3u8. loadValuesAsynchronously won't do any network operations to determine if the URL contains valid HLS files. That's why the "playable" key is always valid:

    static let assetKeysRequiredToPlay = [
        "playable",
        "hasProtectedContent"
    ]
    

    However though, if I also add some playback information such as "duration" and "tracks", then it will fail if there isn't any network connection because it will then need to actually load the information. More detail refer to this answer: https://stackoverflow.com/a/31418812/1035008