Search code examples
iosswiftavplayer

Detect file streaming finished and ready to play with avplayer


I am playing audio file from remote server with avplayer. When i play this, first avplayer stream from the url and then play the file. Now I just want to detect when file streaming is finished and started to play.

Here is my code:

try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)

player = AVPlayer(url: down_url)
player.addObserver(self, forKeyPath: "status", options: NSKeyValueObservingOptions.new, context: nil)
player.volume = 1.0
player.play()


override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if keyPath == "rate" {
        if player.rate > 0 {
            print("player started")
        }
    }
}

I used this code to detect but it print "player started" only once when avplayer started to streaming. But i can't detect when avplayer started to play.


Solution

  • Register as an observer of the player item's status property

    playerItem.addObserver(self, forKeyPath: #keyPath(AVPlayerItem.status), options: [.old, .new], context: &playerItemContext)
    

    and this method will be call

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    
        // Only handle observations for the playerItemContext
        guard context == &playerItemContext else {
            super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
            return
        }
    
    
        // Observer for Player status
        if keyPath == #keyPath(AVPlayerItem.status) {
            let status: AVPlayerItem.Status
            if let statusNumber = change?[.newKey] as? NSNumber {
                status = AVPlayerItem.Status(rawValue: statusNumber.intValue)!
            } else {
                status = .unknown
            }
    
            // Switch over status value
            switch status {
            case .readyToPlay:
                // Player item is ready to play.
                player.play()
                playerControlsView.setPlayerControlsReady()
            case .failed:
                // Player item failed. See error.
                print("Fail")
            case .unknown:
                // Player item is not yet ready.
                print("unknown")
            }
        }
    
    }
    

    Add Observer to monitor when the player Finish playing

    NotificationCenter.default.addObserver(self, selector:#selector(self.playerDidFinishPlaying(note:)),name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: player.currentItem)
    

    This method will call when player finish playing

    @objc func playerDidFinishPlaying(note: NSNotification){
            print("Finished Playing")
    }
    

    And Don't forget to remove the Observer when your done with player

    NotificationCenter.default.removeObserver(self)