AVPlayer playing video 6x or more faster than normal rate

0

I have a TV app which is used in Fitness industry where 6 smart TVs connected to Apple TVs and the App playing videos from a local server. Unitl tvOS 17.0 everything was smooth but soon after that we are facing a strange issue in that sometimes same Video is playing 6x or more faster than normal rate only in 1 random TV. I can see 12 min video finished playing in 1.3 min.

Video Codecs: MPEG-4 AAC, H.264. Is these format affects speed in Apple TV?

TVs are initially runs Intro videos, then warm up, then exercise and at last cooldown. I added the code for exercise background timer video where I am facing issue. On top on background video there are other 4 videos playing in loop. Please find attached image. I am using AVPlayer, Swift 5, Xcode 5 and tvOS 17.0, Apple TV 4K.

code-block

import UIKit import AVKit import AVFoundation

class ViewController: UIViewController {

@IBOutlet weak var workoutCircuitContainerView: UIView!

var workoutCircuitPlayerItem: AVPlayerItem?
var workoutCircuitPlayerLayer: AVPlayerLayer?
var workoutCircuitPlayer: AVPlayer?
var isWorkoutCircuitPlayerObserverAdded: Bool = false
private var workoutCircuitObserverContext = 0

override func viewDidLoad() {
    super.viewDidLoad()
}

override func viewWillAppear(_ animated: Bool) {
    initializeWorkoutCircuitPlayer()
}

func initializeWorkoutCircuitPlayer() {
    workoutCircuitPlayer?.pause()
    workoutCircuitPlayerLayer?.removeFromSuperlayer()
    self.removeWorkoutCircuitPlayerObservers()
    startWorkoutCircuitPlayer()
}

func startWorkoutCircuitPlayer() {
    guard let streamURL = URL(string: "http://192.168.1.116:3001/videos/CARDIO_Work_Circuit1.mp4") else {
        return
    }
    self.workoutCircuitPlayerItem = AVPlayerItem(url: streamURL as URL)
    self.workoutCircuitPlayer = AVPlayer(playerItem: self.workoutCircuitPlayerItem)
    self.workoutCircuitPlayerLayer = AVPlayerLayer(player: self.workoutCircuitPlayer!)
    self.workoutCircuitPlayerLayer!.videoGravity = AVLayerVideoGravity(rawValue: AVLayerVideoGravity.resizeAspectFill.rawValue)
    self.workoutCircuitPlayerLayer!.frame = self.workoutCircuitContainerView.bounds
    self.workoutCircuitContainerView.layer.addSublayer(self.workoutCircuitPlayerLayer!)
    self.workoutCircuitPlayer!.addObserver(self, forKeyPath: "timeControlStatus", options: [.old, .new], context: nil)
    self.playWorkoutCircuitPlayer()
    self.addWorkoutCircuitPlayerObservers()
}

func playWorkoutCircuitPlayer() {
   workoutCircuitPlayer?.play()
}

func addWorkoutCircuitPlayerObservers() {
    if !isWorkoutCircuitPlayerObserverAdded {
        workoutCircuitPlayer?.addObserver(self,
                                          forKeyPath: #keyPath(AVPlayerItem.status),
                                          options: [.old, .new],
                                          context: &workoutCircuitObserverContext)
        NotificationCenter.default.addObserver(self, selector: #selector(self.workoutCircuitPlayerDidFinishPlaying), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: workoutCircuitPlayer?.currentItem)
        NotificationCenter.default.addObserver(self, selector: #selector(self.workoutCircuitPlayerStalled(note:)), name: .AVPlayerItemPlaybackStalled, object: self.workoutCircuitPlayer?.currentItem)
        isWorkoutCircuitPlayerObserverAdded = true
    }
}

@objc func workoutCircuitPlayerDidFinishPlaying(notification: NSNotification) {
    // play cool down videos code
}

@objc func workoutCircuitPlayerStalled(note: NSNotification) {
    if let playerItem = note.object as? AVPlayerItem {
        playerItem.seek(to: (workoutCircuitPlayer?.currentTime())!, completionHandler: nil)
        self.workoutCircuitPlayer!.play()
    }
}

func removeWorkoutCircuitPlayerObservers() {
    if isWorkoutCircuitPlayerObserverAdded {
        workoutCircuitPlayer?.removeObserver(self, forKeyPath: #keyPath(AVPlayerItem.status), context: &workoutCircuitObserverContext)
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: workoutCircuitPlayer?.currentItem)
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.AVPlayerItemPlaybackStalled, object: workoutCircuitPlayer?.currentItem)
        isWorkoutCircuitPlayerObserverAdded   = false
    }
}

}