89

Is it possible get playing time and total play time in AVPlayer? If yes, how can I do this?

Voloda2
  • 12,359
  • 18
  • 80
  • 130

10 Answers10

179

You can access currently played item by using currentItem property:

AVPlayerItem *currentItem = yourAVPlayer.currentItem;

Then you can easily get the requested time values

CMTime duration = currentItem.duration; //total time
CMTime currentTime = currentItem.currentTime; //playing time

Swift 5:

if let currentItem = player.currentItem {
    let duration = CMTimeGetSeconds(currentItem.duration)
    let currentTime = CMTimeGetSeconds(currentItem.currentTime())

    print("Duration: \(duration) s")
    print("Current time: \(currentTime) s")
}
Denis Kutlubaev
  • 15,320
  • 6
  • 84
  • 70
Bartosz Ciechanowski
  • 10,293
  • 5
  • 45
  • 60
  • 16
    there is also convenient method CMTimeGetSeconds to get NSTimeInterval: NSTimeInterval duration = CMTimeGetSeconds(currentItem.duration); NSTimeInterval currentTime = CMTimeGetSeconds(currentItem.currentTime); – slamor Jan 12 '15 at 15:26
  • i had to set call it in main queue for it to return the right value (or whatever queue your avplayer is running in). – Pnar Sbi Wer Apr 17 '15 at 15:31
  • 1
    how to give this propety to LABEL? – Mr. Bond Mar 21 '16 at 09:20
  • 1
    i am playing song from url . but at CMTime duration and CMTime currentTime i am getting 0 . what is the problem here for 0 value ? does anyone know the solution ? – Moxarth Sep 19 '17 at 13:41
  • NSTimeInterval duration3 = CMTimeGetSeconds(currentItem.duration); NSTimeInterval currentTime3 = CMTimeGetSeconds(currentItem.currentTime); NSLog(@"%f and %f",duration3,currentTime3); self.playbackSlider.value = currentTime3/duration3; – Genevios Apr 03 '18 at 17:23
  • How come the `currentTime().seconds` is sometimes greater than the `duration`? I can't find the answer and this happens every time when the asset plays to the end (I fetch the `currentTime` every half a second): `currentTime: 19.50039306 of 20.0 -> currentTime: 20.0002372 of 20.0 -> currentTime: 20.000558334 of 20.0` – JastinBall Feb 23 '23 at 11:27
24
_audioPlayer = [self playerWithAudio:_audio];
_observer =
[_audioPlayer addPeriodicTimeObserverForInterval:CMTimeMake(1, 2)
                                           queue:dispatch_get_main_queue()
                                      usingBlock:^(CMTime time)
                                      {
                                          _progress = CMTimeGetSeconds(time);
                                      }];
Tim Kozak
  • 4,026
  • 39
  • 44
22

Swift 3

let currentTime:Double = player.currentItem.currentTime().seconds

You can get the seconds of your current time by accessing the seconds property of the currentTime(). This will return a Double that represents the seconds in time. Then you can use this value to construct a readable time to present to your user.

First, include a method to return the time variables for H:mm:ss that you will display to the user:

func getHoursMinutesSecondsFrom(seconds: Double) -> (hours: Int, minutes: Int, seconds: Int) {
    let secs = Int(seconds)
    let hours = secs / 3600
    let minutes = (secs % 3600) / 60
    let seconds = (secs % 3600) % 60
    return (hours, minutes, seconds)
}

Next, a method that will convert the values you retrieved above into a readable string:

func formatTimeFor(seconds: Double) -> String {
    let result = getHoursMinutesSecondsFrom(seconds: seconds)
    let hoursString = "\(result.hours)"
    var minutesString = "\(result.minutes)"
    if minutesString.characters.count == 1 {
        minutesString = "0\(result.minutes)"
    }
    var secondsString = "\(result.seconds)"
    if secondsString.characters.count == 1 {
        secondsString = "0\(result.seconds)"
    }
    var time = "\(hoursString):"
    if result.hours >= 1 {
        time.append("\(minutesString):\(secondsString)")
    }
    else {
        time = "\(minutesString):\(secondsString)"
    }
    return time
}

Now, update the UI with the previous calculations:

func updateTime() {
    // Access current item
    if let currentItem = player.currentItem {
        // Get the current time in seconds
        let playhead = currentItem.currentTime().seconds
        let duration = currentItem.duration.seconds
        // Format seconds for human readable string
        playheadLabel.text = formatTimeFor(seconds: playhead)
        durationLabel.text = formatTimeFor(seconds: duration)
    }
}
Brandon A
  • 8,153
  • 3
  • 42
  • 77
16

With Swift 4.2, use this;

let currentPlayer = AVPlayer()
if let currentItem = currentPlayer.currentItem {
    let duration = currentItem.asset.duration
}
let currentTime = currentPlayer.currentTime()
Kemal Can Kaynak
  • 1,638
  • 14
  • 26
16

Swift 4

    self.playerItem = AVPlayerItem(url: videoUrl!)
    self.player = AVPlayer(playerItem: self.playerItem)

    self.player?.addPeriodicTimeObserver(forInterval: CMTimeMakeWithSeconds(1, 1), queue: DispatchQueue.main, using: { (time) in
        if self.player!.currentItem?.status == .readyToPlay {
            let currentTime = CMTimeGetSeconds(self.player!.currentTime())

            let secs = Int(currentTime)
            self.timeLabel.text = NSString(format: "%02d:%02d", secs/60, secs%60) as String//"\(secs/60):\(secs%60)"

    })
}
xuzepei
  • 1,119
  • 11
  • 9
6

Swift 5: Timer.scheduledTimer seems better than addPeriodicTimeObserver if you want to have a smooth progress bar

static public var currenTime = 0.0
static public var currenTimeString = "00:00"

        Timer.scheduledTimer(withTimeInterval: 1/60, repeats: true) { timer in

            if self.player!.currentItem?.status == .readyToPlay {

                let timeElapsed = CMTimeGetSeconds(self.player!.currentTime())
                let secs = Int(timeElapsed)
                self.currenTime = timeElapsed
                self.currenTimeString = NSString(format: "%02d:%02d", secs/60, secs%60) as String


                print("AudioPlayer TIME UPDATE: \(self.currenTime)    \(self.currenTimeString)")
            }
        }
Thyselius
  • 864
  • 1
  • 10
  • 14
  • really, you have to animate smooth progress bars from point to point - it's not so easy. you'd definitely never use a trimer (for any reason) with 1/60 - just use CADisplayLink – Fattie Feb 26 '20 at 16:22
5
     AVPlayerItem *currentItem = player.currentItem;
     NSTimeInterval currentTime = CMTimeGetSeconds(currentItem.currentTime);
     NSLog(@" Capturing Time :%f ",currentTime);
Athul Raj
  • 349
  • 3
  • 11
  • i am playing song from url . but at CMTime duration and CMTime currentTime i am getting 0 . what is the problem here for 0 value ? does anyone know the solution ? – Moxarth Sep 19 '17 at 13:47
5

Swift:

let currentItem = yourAVPlayer.currentItem

let duration = currentItem.asset.duration
var currentTime = currentItem.asset.currentTime
Cœur
  • 37,241
  • 25
  • 195
  • 267
Unis Barakat
  • 876
  • 1
  • 8
  • 23
1

Swift 4.2:

let currentItem = yourAVPlayer.currentItem
let duration = currentItem.asset.duration
let currentTime = currentItem.currentTime()
Matthijs
  • 515
  • 4
  • 8
1

in swift 5+

You can query the player directly to find the current time of the actively playing AVPlayerItem. The time is stored in a CMTime Struct for ease of conversion to various scales such as 10th of sec, 100th of a sec etc In most cases we need to represent times in seconds so the following will show you what you want

let currentTimeInSecs = CMTimeGetSeconds(player.currentTime())
Sven Eberth
  • 3,057
  • 12
  • 24
  • 29