0
votes

I am using an AVPlayer to play an mp3 file. I am using this instead of AVAudioPlayer because it supports playing at speeds outside of the range of 0.0 ... 2.0. However, I want the audio to loop continually, so I am using an AVQueuePlayer and an AVPlayerLooper to play the file. This works when the rate property is positive, but when the reversed playback reaches the beginning of the file, it just stops, instead of going back to the end of the file and continuing to play in reverse. Are there any ways I can keep the player looping? Here's what I'm trying:

 override func viewDidLoad() {
    super.viewDidLoad()

    //Initialize the audio file and audio player

    guard let path = Bundle.main.path(forResource: "sideAMusic.mp3", ofType: nil) else {
        Console.log("Uh oh - no path could be found for filename: \("sideAMusic")")
        return
    }
    let url = URL(fileURLWithPath: path)
    let playerItem = AVPlayerItem(url: url)
    self.sideAPlayer = AVQueuePlayer(playerItem: playerItem)
    sideALooper = AVPlayerLooper(player: sideAPlayer!, templateItem: playerItem)
    sideAPlayer?.volume = 1
    sideAPlayer?.play()
}

// Use a slider in the range of -4 ... 4 to set the playback speed
@IBAction func speedSlider(_ sender: UISlider) {
    self.sideAPlayer?.rate = sender.value
}

1

1 Answers

0
votes

You should add a periodic time observer. Here is the link to documentation.

You should also check here how to observe times.

Also, here is a code sample.

    func addPeriodicTimeObserver() {
        // Notify every 0.05 second
        let timeScale = CMTimeScale(NSEC_PER_SEC)
        let time = CMTime(seconds: 0.05, preferredTimescale: timeScale)

        timeObserverToken = player.addPeriodicTimeObserver(forInterval: time,
                                                          queue: .main) {
            [weak self] currentTime in
              if CMTimeCompare(currentTime, CMTime.zero) == 0 {
                   //The track reached the beginning, you should seek player to the end time
                   self?.player.seek(to: self?.playerItem.duration, toleranceBefore: .zero, toleranceAfter: .zero)
                   self?.player.play()
              }
        }
    }

    func removePeriodicTimeObserver() {
        if let timeObserverToken = timeObserverToken {
            player.removeTimeObserver(timeObserverToken)
            self.timeObserverToken = nil
        }
    }