fswedison
fswedison

Reputation: 21

current time after AVPlayer seek is incorrect

func seekFullRead(seconds: Float64, completion: (() -> ())? = nil) {
    let targetTime:CMTime = CMTimeMakeWithSeconds(seconds, preferredTimescale: 60000)
    fullReadPlayer?.currentItem?.seek(to: targetTime, toleranceBefore: .zero, toleranceAfter: .zero, completi[enter image description here][1]onHandler: { (finish) in
        if finish {
            completion?()
        }
    })
}

fullReadTimeObserver = fullReadPlayer?.addPeriodicTimeObserver(forInterval: CMTimeMake(value: 1, timescale: 10), queue: DispatchQueue.main, using: { [weak self](time) in
        guard let self = self else { return }
        if self.fullReadPlayer?.status == .readyToPlay {
            self.delegate?.audioPlayer(self, didUpdateCurrentTime: time.seconds, teach: nil)
        }
    })

When I seek to 4.57 seconds, the correct current time will be displayed first, then the current time will be 0.2 seconds forward, but playback will start after the current time will be 0.2 seconds forward.

Logs:

current time: 1.30104062

current time: 1.401042787

seek to : 4.579999923706055

current time: 1.498295786

current time: 4.579983333333334

current time: 4.319330793

current time: 4.319642834

current time: 4.401050459

current time: 4.501045084

current time: 4.601038959

Upvotes: 2

Views: 1502

Answers (1)

Jianyuan Chen
Jianyuan Chen

Reputation: 63

I think NSGangster had the point. Observer timer and seek are on different processes. What this means to me is I will have to handle the discrepancies by myself.

I did not find an answer on the internet and had no luck in finding out a way to make this correct, but I did manage to find a workaround: I could use a variable like 'isSeekInProgress' to mark whether to update the progress bar UI. Illustrated below:

var isSeekInProgress: Bool = false  // Marker  

let targetTime:CMTime = CMTimeMakeWithSeconds(seconds, preferredTimescale: 60000)
isSeekInProgress = true // Mark
fullReadPlayer?.currentItem?.seek(to: targetTime, toleranceBefore: .zero, toleranceAfter: .zero, completi[enter image description here][1]onHandler: { (finish) in
    if finish {
        isSeekInProgress = false // Unmark
        completion?()
    }
})

Some people pause the player while seeking then resume playback in the completion block, but this won't work in the case you want the playback to keep going while scrubbing. The above example is fairly painless, and all you have to do is check:

if !playbackManager.isSeekInProgress {
    progressSlider.value = playbackManager.progress
}

And during the next periodic observer notification, your progress will be updated.

Upvotes: 3

Related Questions