Chris
Chris

Reputation: 312

playerItemDidReachEnd reliability issues

I playback a video asset via avplayer and want to perform an action when the item has finished playing. For some reason, playerItemDidReachEnd doesn't get called and I'm completely lost as to why. I've also tried addPeriodicTimeObserver to the player and sometimes it works, sometimes it doesn't.

Below is my code. Any guidance would be appreciated.

    func setupVideo(with asset: AVAsset) {
    
    let video = AVPlayerItem(asset: asset)
    video.addObserver(self, forKeyPath: "status", options: [.new, .initial], context: nil)
    
    avPlayerPlayback.replaceCurrentItem(with: video)

    avPlayerPlayback.actionAtItemEnd = .none

    let playbackLayer = AVPlayerLayer(player: avPlayerPlayback)
    playbackLayer.frame = capturedVideoPlaybackView.frame
    playbackLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
    capturedVideoPlaybackView.layer.addSublayer(playbackLayer)
    
    print("Player status: \(avPlayerPlayback.status.rawValue)")
    print("Player item duration: \(CMTimeGetSeconds(avPlayerPlayback.currentItem?.duration ?? CMTime.zero))")
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
   
    if keyPath == "status" {
        if let item = object as? AVPlayerItem {
            if item.status == .readyToPlay {
                // The AVPlayerItem is ready to play
                print("Item is ready to play")
                DispatchQueue.main.async { [weak self] in
                    
                    guard let self = self else { return }
                    
                    NotificationCenter.default.addObserver(self,
                                                           selector: #selector(playerItemDidReachEnd(notification:)),
                                                           name: .AVPlayerItemDidPlayToEndTime,
                                                           object: self.avPlayerPlayback.currentItem)
                    
                    self.toggleMedia(shouldHideVideo: false)
                    self.playVideo()
                    
                    print("Player status: \(avPlayerPlayback.status.rawValue)")
                    print("Player item duration: \(CMTimeGetSeconds(avPlayerPlayback.currentItem?.duration ?? CMTime.zero))")
                    print("playing video")
                }
                // Perform any additional setup or start playback
            } else if item.status == .failed {
                // Handle failure
                print("Player item failed: \(String(describing: item.error?.localizedDescription))")
            }
        }
    }
}

func playVideo() {
   
    DispatchQueue.main.async { [weak self] in
        
        guard let self = self else { return }
        
//            self.avPlayerPlaybackTimeObserver =
//
//            self.avPlayerPlayback.addPeriodicTimeObserver(forInterval: CMTime(value: 1, timescale: 2) , queue: .main, using: { time in
//
//                if let currentItem = self.avPlayerPlayback.currentItem {
//
//                    let totalDuration = CMTimeGetSeconds(currentItem.duration)
//                    let secondsElapsed = CMTimeGetSeconds(time)
//
//                    print(totalDuration)
//                    print(secondsElapsed)
//
//                    let progress = CGFloat(secondsElapsed / totalDuration)
//
//                    if progress >= 1 {
//                        self.handlePlaybackItemCompletion()
//                    }
//                }
//            })
                                            
        self.avPlayerPlayback.play()
    }
}

@objc func playerItemDidReachEnd(notification: Notification) {
    // This function is called when the AVPlayer finishes playing the item
    print("Playback finished")
    handlePlaybackItemCompletion() // Call your completion handling method
}

Upvotes: 0

Views: 40

Answers (0)

Related Questions