David Cordero

Prevent fast-forward in tvOS

Published on 05 Aug 2021

Due to legal restrictions, or content agreements, it is a very common use case in the TV industry having to prevent forward-seeking for certain contents.

At Zattoo, we are not an exception, and we also had to implement this playback limitation in our Apps.

Sadly, when trying to implement this behaviour in tvOS, we found out that the only way provided by Apple to prevent forward-seeking content is by using the property requiresLinearPlayback of AVPlayerViewController.

The problem is that setting this property does not only prevent seeking the content forward but also backward.

Let the users rewind

Trying to limit the functionality to our users as little as possible, we made some investigations and we found out a way to limit seeking forward while still offering the possibility to seek the content backward.

The solution is based on the method timeToSeekAfterUserNavigatedFrom of AVPlayerViewControllerDelegate.

This delegate method is called when the user of our App tries to seek in an instace of AVPlayerViewController, and it allows returning a custom target time to seek.

Implementing this method, we can disable forward seeking simply returning the current playback position when the user tries to seek forwards.

extension PlayerWithoutFastForwardViewController: AVPlayerViewControllerDelegate {
    
    func playerViewController(_ playerViewController: AVPlayerViewController, timeToSeekAfterUserNavigatedFrom oldTime: CMTime, to targetTime: CMTime) -> CMTime {
        guard let currentItem = playerViewController.player?.currentItem else { return targetTime }
        
        let isForwarding = targetTime.seconds > oldTime.seconds
        if isForwarding {
            return currentItem.currentTime()
        }

        return targetTime
    }
}

Notice that we are not returning oldTime but the current playback position (currentItem.currentTime). This is because otherwise, the user could still skip the content by pressing the fast forward button several times in a row in their remote controls.

Fast Forward

Implementing the previous method is not enought, because at this point the user could still skip content triggering a long press on the right button of Siri Remote. This gesture activates the fast forward mode in the player.

To avoid fast forward content this way, we need to define and to use a custom AVPlayerItem that overrides the values of canPlayFastForward and canPlaySlowForward to return false.

class PlayerItemWithFFDisabled: AVPlayerItem {
    override var canPlayFastForward: Bool {
        false
    }

    override var canPlaySlowForward: Bool {
        false
    }
}

With this change, the user won’t be able to fast forward any more using this gesture either. And that’s all, we are done, except for one detail…

It looks like a bug

At this point, we managed to achieve our goal. Our users will not be able to skip content forward anymore while we still offer them the possibility to seek backward.

But this solution has a problem, it looks like a bug. When the user tries to skip content forward we send them back to their current position and they do not know why.

To make it easier to understand what’s going on, at Zattoo we decided to show a toast message with a hint message explaining the reason why we are sending the user back.

Show me the code

You can find here a project showing a working implementation of the method described in this post.