diff --git a/Framework/Sources/Controllers/SRGMediaPlayerController.m b/Framework/Sources/Controllers/SRGMediaPlayerController.m index 81780d22..20d110d1 100644 --- a/Framework/Sources/Controllers/SRGMediaPlayerController.m +++ b/Framework/Sources/Controllers/SRGMediaPlayerController.m @@ -172,30 +172,34 @@ - (void)setPlayer:(AVPlayer *)player } }; - // If a segment is targeted, add a small offset so that playback is guaranteed to start within the segment SRGPosition *startPosition = self.startPosition; - if (self.targetSegment) { - startPosition = SRGMediaPlayerControllerOffset(startPosition, CMTimeMakeWithSeconds(SRGSegmentSeekOffsetInSeconds, NSEC_PER_SEC)); - } - - // Take into account tolerance at the end of the content being played. If near the end enough, start - // at the default position instead. - CMTimeRange timeRange = self.targetSegment ? self.targetSegment.srg_timeRange : self.timeRange; - CMTime tolerance = SRGMediaPlayerEffectiveEndTolerance(self.endTolerance, self.endToleranceRatio, CMTimeGetSeconds(timeRange.duration)); - CMTime toleratedStartTime = CMTIME_COMPARE_INLINE(startPosition.time, >=, CMTimeSubtract(timeRange.duration, tolerance)) ? kCMTimeZero : startPosition.time; - // Positions in segments are relative. If not within a segment, they are absolute (relative positions - // are misleading for a DVR stream with a sliding window, and match the absolute position in other cases) - if (self.targetSegment) { - toleratedStartTime = CMTimeAdd(toleratedStartTime, timeRange.start); - } - SRGPosition *toleratedPosition = [SRGPosition positionWithTime:toleratedStartTime toleranceBefore:startPosition.toleranceBefore toleranceAfter:startPosition.toleranceAfter]; - - SRGPosition *seekPosition = SRGMediaPlayerControllerPositionInTimeRange(toleratedPosition, timeRange); - if (CMTIME_COMPARE_INLINE(seekPosition.time, ==, kCMTimeZero)) { + // Default position. Nothing to do. + if (CMTIME_COMPARE_INLINE(self.startPosition.time, ==, kCMTimeZero) && ! self.targetSegment) { completionBlock(YES); } + // Non-default start position. Calculate a valid position to seek to. else { + // If a segment is targeted, add a small offset so that playback is guaranteed to start within the segment + if (self.targetSegment) { + startPosition = SRGMediaPlayerControllerOffset(startPosition, CMTimeMakeWithSeconds(SRGSegmentSeekOffsetInSeconds, NSEC_PER_SEC)); + } + + // Take into account tolerance at the end of the content being played. If near the end enough, start + // at the default position instead. + CMTimeRange timeRange = self.targetSegment ? self.targetSegment.srg_timeRange : self.timeRange; + CMTime tolerance = SRGMediaPlayerEffectiveEndTolerance(self.endTolerance, self.endToleranceRatio, CMTimeGetSeconds(timeRange.duration)); + CMTime toleratedStartTime = CMTIME_COMPARE_INLINE(startPosition.time, >=, CMTimeSubtract(timeRange.duration, tolerance)) ? kCMTimeZero : startPosition.time; + + // Positions in segments are relative. If not within a segment, they are absolute (relative positions + // are misleading for a DVR stream with a sliding window, and match the absolute position in other cases) + if (self.targetSegment) { + toleratedStartTime = CMTimeAdd(toleratedStartTime, timeRange.start); + } + SRGPosition *toleratedPosition = [SRGPosition positionWithTime:toleratedStartTime toleranceBefore:startPosition.toleranceBefore toleranceAfter:startPosition.toleranceAfter]; + + SRGPosition *seekPosition = SRGMediaPlayerControllerPositionInTimeRange(toleratedPosition, timeRange); + // Call system method to avoid unwanted seek state in this special case [player seekToTime:seekPosition.time toleranceBefore:seekPosition.toleranceBefore toleranceAfter:seekPosition.toleranceAfter completionHandler:^(BOOL finished) { completionBlock(finished); diff --git a/Framework/Sources/Controllers/SRGMediaPlayerViewController.m b/Framework/Sources/Controllers/SRGMediaPlayerViewController.m index 6ac38566..de54c5d0 100644 --- a/Framework/Sources/Controllers/SRGMediaPlayerViewController.m +++ b/Framework/Sources/Controllers/SRGMediaPlayerViewController.m @@ -361,7 +361,14 @@ - (BOOL)canSkipBackwardFromTime:(CMTime)time return NO; } - SRGMediaPlayerStreamType streamType = self.controller.streamType; + SRGMediaPlayerController *controller = self.controller; + SRGMediaPlayerPlaybackState playbackState = controller.playbackState; + + if (playbackState == SRGMediaPlayerPlaybackStateIdle || playbackState == SRGMediaPlayerPlaybackStatePreparing) { + return NO; + } + + SRGMediaPlayerStreamType streamType = controller.streamType; return (streamType == SRGMediaPlayerStreamTypeOnDemand || streamType == SRGMediaPlayerStreamTypeDVR); } @@ -372,8 +379,15 @@ - (BOOL)canSkipForwardFromTime:(CMTime)time } SRGMediaPlayerController *controller = self.controller; - return (controller.streamType == SRGMediaPlayerStreamTypeOnDemand && CMTimeGetSeconds(time) + SRGMediaPlayerViewControllerForwardSkipInterval < CMTimeGetSeconds(controller.player.currentItem.duration)) - || (controller.streamType == SRGMediaPlayerStreamTypeDVR && ! controller.live); + SRGMediaPlayerPlaybackState playbackState = controller.playbackState; + + if (playbackState == SRGMediaPlayerPlaybackStateIdle || playbackState == SRGMediaPlayerPlaybackStatePreparing) { + return NO; + } + + SRGMediaPlayerStreamType streamType = controller.streamType; + return (streamType == SRGMediaPlayerStreamTypeOnDemand && CMTimeGetSeconds(time) + SRGMediaPlayerViewControllerForwardSkipInterval < CMTimeGetSeconds(controller.player.currentItem.duration)) + || (streamType == SRGMediaPlayerStreamTypeDVR && ! controller.live); } - (void)skipBackwardFromTime:(CMTime)time withCompletionHandler:(void (^)(BOOL finished))completionHandler