7
votes

I have an AVPlayer which is streaming a live HLS stream.

When the user multitasks the app, I see the play rate drop to 0.0 (paused), when the user comes back it return to 1.0(play), but starts playing from the point it was paused.

What is the best way to force the player back to live without restarting the stream completely? Is there a seekToTime method that handles a closest to live time parameter?

Thanks!

7

7 Answers

8
votes

I use:

 double time = MAXFLOAT;
 [player seekToTime: CMTimeMakeWithSeconds(time, NSEC_PER_SEC)];

Works well in my app.

3
votes

Assuming player is an AVPlayer instance:

CMTimeRange seekableRange = [player.currentItem.seekableTimeRanges.lastObject CMTimeRangeValue];
CGFloat seekableStart = CMTimeGetSeconds(seekableRange.start);
CGFloat seekableDuration = CMTimeGetSeconds(seekableRange.duration);
CGFloat livePosition = seekableStart + seekableDuration;

[player seekToTime:CMTimeMake(livePosition, 1)];
1
votes

Swift 3.0 Version

public func resumeLive() {
    guard let livePosition = player.currentItem?.seekableTimeRanges.last as? CMTimeRange else {
        return
    }
    player.seek(to:CMTimeRangeGetEnd(livePosition))
}
0
votes

Swift version of Karim Mourra's answer:

let seekableRanges = player.currentItem!.seekableTimeRanges
guard seekableRanges.count > 0 else {
  return
}

let range = seekableRanges.last!.CMTimeRangeValue
let livePosition = range.start + range.duration

let minus = CMTimeMakeWithSeconds(Float64(timeOffset), Int32(NSEC_PER_SEC))
let time = livePosition - minus

player.seekToTime(time)
0
votes

No need to convert to floating point if you use Apple's CMTimeRange manipulation functions:

NSValue *value = player.currentItem.seekableTimeRanges.lastObject;
if (value) {
    CMTimeRange seekableRange = [value CMTimeRangeValue];
    CMTime latestTime = CMTimeRangeGetEnd(seekableRange);
    [player seekToTime:latestTime];
} else {
    // there are no seekable time ranges
}

EDIT: please upvote Fabian's comment below

0
votes

Swift version of Igor Kulagin answer:

player.seek(to: kCMTimePositiveInfinity)
player.play()

Works perfectly in any condition. Other solutions gave me NaN error calculating livePosition value, or {INVALID} error working directly with CMTime.

0
votes

Swift 4 version:

if let seekableRange = player.currentItem?.seekableTimeRanges.last?.timeRangeValue {
    let seekableStart = seekableRange.start
    let seekableDuration = seekableRange.duration
    let livePosition = seekableStart + seekableDuration

    player.seek(to: livePosition, completionHandler: { [weak self] _ in
        self?.player.play()
    })
}