C0D3
C0D3

Reputation: 6549

tvOS PlayPause button tap gesture on AVPlayerViewController

I have added a tapGestureRecognizer for the Play/Pause button and it works on a custom player (meaning a AVPlayer inserted in a ViewController instance) as such:

lazy var playPauseButtonTap: UITapGestureRecognizer = {
    let gesture = UITapGestureRecognizer(target: self, action: #selector(playPauseTapped))
    gesture.allowedPressTypes = [NSNumber(value: UIPress.PressType.playPause.rawValue)]
    return gesture
}()

@objc private func playPauseTapped() {
    print("HELLO PLAY PAUSE TAPPED")
    togglePlayPause()
}
private func togglePlayPause() {
    switch avPlayer.timeControlStatus {
    case .playing:
        avPlayer.pause()
    case .paused:
        avPlayer.play()
    case .waitingToPlayAtSpecifiedRate:
        break
    @unknown default:
        break
    }
}

override func viewDidLoad() {
    super.viewDidLoad()

    let playerLayer = AVPlayerLayer(player: avPlayer)
    playerLayer.frame = self.view.bounds
    self.view.layer.addSublayer(playerLayer)
    avPlayer.play()

    self.view.addGestureRecognizer(playPauseButtonTap)
}

This works! But when the same code is run on a class that inherits from AVPlayerViewController (except the part where we insert the AVPlayerLayer because AVPlayerViewController handles that part), when the button is tapped to pause, the gesture recognizer code won't get called, when the button is tapped to play/resume it DOES get called.

I need to know when the user pauses playback. Is there any way to get this to work using the AVPlayerViewController?

I'm not looking to do swizzling or use any private APIs as Apple will not take that lightly however, I'd be interested to learn if anyone has made it work using some hacky solution that way.

NOTE: I also found out if you have this call: UIApplication.shared.beginReceivingRemoteControlEvents() in your app, this makes a gesture recognizer completely ignore the play/pause button taps.

Thanks in advance.

Upvotes: 1

Views: 206

Answers (1)

iUrii
iUrii

Reputation: 13758

If you want to track timeControlStatus of the AVPlayer you should observe it with Key-Value Observing instead of handling gestures etc. because AVPlayerViewController has other buttons.

import AVKit

let observer: NSKeyValueObservation?

let url = URL(string: "https://bitdash-a.akamaihd.net/content/MI201109210084_1/m3u8s/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.m3u8")!
let player = AVPlayer(url: url)
player.play()

let playerController = AVPlayerViewController()
playerController.player = player

observer = player.observe(\.timeControlStatus, options: [.new]) { player, change in
  switch player.timeControlStatus {
    case .paused:
      print("paused")

    case .playing:
      print("playing")
      
    case .waitingToPlayAtSpecifiedRate:
      print("waitingToPlayAtSpecifiedRate")
      
    @unknown default:
      break
  }
}

PlaygroundPage.current.liveView = playerController
PlaygroundPage.current.needsIndefiniteExecution = true

NOTE: observer variable must be stored anywhere on your controller or globally.

Upvotes: 1

Related Questions