Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect the toggle on the display of playback controls with AVPlayerViewController?

I'd like to know if it is possible to detect when the playback controls appear or disappear from the AVPlayerViewController view. I'm trying to add a UI element on my player that must follow the playback controls display. Appearing only when the controls are displayed, disappearing otherwise

I don't seem to find any value that I can observe on AVPlayerViewController to achieve this nor any callbacks or delegate methods.

My project is in Swift.

like image 881
Martin Avatar asked Mar 12 '19 15:03

Martin


1 Answers

A simple way to observe and respond to the playback changes is to use key-value observing (KVO). In your case, observe AVPlayer's timeControlStatus or rate property.

e.g.:

{
  // 1. Setup AVPlayerViewController instance (playerViewController)

  // 2. Setup AVPlayer instance & assign it to playerViewController

  // 3. Register self as an observer of the player's `timeControlStatus` property

  // 3.1. Objectice-C
  [player addObserver:self
           forKeyPath:@"timeControlStatus"
              options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew // NSKeyValueObservingOptionOld is optional here
              context:NULL];

  // 3.2. Swift
  player.addObserver(self,
                     forKeyPath: #keyPath(AVPlayer.timeControlStatus),
                     options: [.old, .new], // .old is optional here
                     context: NULL)
}

To be notified of state changes, you implement the -observeValueForKeyPath:ofObject:change:context: method. This method is invoked whenever the timeControlStatus value changes.

// Objective-C
- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary <NSKeyValueChangeKey, id> *)change
                       context:(void *)context
{
  if ([keyPath isEqualToString:@"timeControlStatus"]) {
    // Update your custom UI here depend on the value of `change[NSKeyValueChangeNewKey]`:
    // - AVPlayerTimeControlStatusPaused
    // - AVPlayerTimeControlStatusWaitingToPlayAtSpecifiedRate
    // - AVPlayerTimeControlStatusPlaying
    AVPlayerTimeControlStatus timeControlStatus = (AVPlayerTimeControlStatus)[change[NSKeyValueChangeNewKey] integerValue];
    // ...

  } else {
    [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
  }
}

// Swift
override func observeValue(forKeyPath keyPath: String?,
                           of object: Any?,
                           change: [NSKeyValueChangeKey : Any]?,
                           context: UnsafeMutableRawPointer?)
{
  if keyPath == #keyPath(AVPlayer.timeControlStatus) {
    // Deal w/ `change?[.newKey]`
  } else {
    super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
  }
}

And last most important step, remember to remove the observer when you don't need it anymore, generally at -dealloc:

[playerViewController.player removeObserver:self forKeyPath:@"timeControlStatus"];

Btw, you can also observe AVPlayer's rate property, cause -play equivalents to setting the value of rate to 1.0, and -pause equivalent to setting the value of rate to 0.0.

But in your case, I think timeControlStatus makes more sense.


There's an official DOC for further reading (but just "Ready to Play", "Failed" & "Unknown" states, useless here): "Responding to Playback State Changes" .

Hope it helps.

like image 163
Kjuly Avatar answered Nov 08 '22 05:11

Kjuly