2

I am wondering if the following is really the best way to know when a video is ready to play: Currently what I do is if currentMedia.playerQueue?.status.rawValue == 1 { I play, else (video has not loaded yet) I will show loading icon and then do the following to observe for when the video is ready to play:

I create a AVPlayer using the same video url and then when its ready I will call the playCurentMedia() method to play vid.

currentMedia.avPlayer = AVPlayer(url: currentMedia.videoURL!)

currentMedia.avPlayer!.addObserver(self, forKeyPath: "status", options: [.new, .initial], context: &P2SheetViewController.playerStatusContext)

Does this stragtegy ahve any flaws? Or is it a good solution?

How can I then observe for a change so I can show the video when it's ready?

Currently, I am only able to set up a AVPlayer alongside the queue so that I can observe for its change...

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    print("observe KVO")
    // Only handle observations for the playerItemContext
    guard context == &P2SheetViewController.playerStatusContext else {
        super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
        return
    }

    if keyPath == #keyPath(AVPlayer.status) {
        let status: AVPlayer.Status
        if let statusNumber = change?[.newKey] as? NSNumber {
            status = AVPlayer.Status(rawValue: statusNumber.intValue)!
        } else {
            status = .unknown
        }

        //Switch over status value
        switch status {
        case .readyToPlay:
            print("READY TO PLAY")
            GlobalSharedData.shared.videoAllSetToGoMedia1 = true

            if GlobalSharedData.shared.p2Media1VideoWasNotReadyWhenPressedView {
                baseVC.playVideoControlForP2()
            }

            break
        // Player item is ready to play.
        case .failed:
            print(".UKNOWN")

            break
        // Player item failed. See error.
        case .unknown:
            print(".UKNOWN")

            break
            // Player item is not yet ready.
        }

    }
}

1 Answers1

2

According to the official AVPlayer documentation, there are two approaches you can use to observe a player’s state:

General State Observations: You can use Key-value observing (KVO) to observe state changes to many of the player’s dynamic properties, such as its currentItem or its playback rate. You should register and unregister for KVO change notifications on the main thread. This avoids the possibility of receiving a partial notification when making a change on another thread. AVFoundation invokes observeValue(forKeyPath:of:change:context:) on the main thread, even when making the change operation on another thread.

Timed State Observations: KVO works well for general state observations, but isn’t intended for observing continuously changing state like the player’s time. AVPlayer provides two methods to observe time changes:

  • addPeriodicTimeObserver(forInterval:queue:using:)
  • addBoundaryTimeObserver(forTimes:queue:using:)

These methods let you observe time changes either periodically or by boundary, respectively. As changes occur, invoke the callback block or closure you supply to these methods to give you the opportunity to take some action such as updating the state of your player’s user interface.

Also, see AVPlayer status property note:

The player’s status does not indicate its readiness to play a specific player item. You should instead use the status property of AVPlayerItem to make that determination.

So, if you want to know when the specific video is loaded and ready to play you should create AVPlayerItem and observe its status property. When the player item’s media has been loaded and is ready for use, its status will change to AVPlayerItem.Status.readyToPlay.

Community
  • 1
  • 1
Alex D.
  • 671
  • 3
  • 12