Is KVO on AVPlayerItem.loadedTimeRanges possible?
Asked Answered
B

3

5

Apples documentation alludes to it, but how do you set up key-value observation for the loadedTimeRanges property of AVPlayerItem? That property is an NSArray that doesn't change, so you can't just use playerItem addObserver:self forKeyPath:@"loadedTimeRanges ...

Or is there another way to get notifications or updates whenever this changes?

Babul answered 25/1, 2012 at 0:27 Comment(0)
T
7

Actually, I'm using KVO for loadedTimeRanges without any trouble. Maybe you're just not setting the right options? The following is a very slight modification of some of the code in Apple's AVPlayerDemo, and it's working quite nicely for me.

//somewhere near the top of the file
NSString * const kLoadedTimeRangesKey   = @"loadedTimeRanges";
static void *AudioControllerBufferingObservationContext = &AudioControllerBufferingObservationContext;


- (void)someFunction
{  
    // ...

    //somewhere after somePlayerItem has been initialized
    [somePlayerItem addObserver:self
                       forKeyPath:kLoadedTimeRangesKey
                          options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
                          context:AudioControllerBufferingObservationContext];

    // ...
}

- (void)observeValueForKeyPath:(NSString*) path 
                  ofObject:(id)object 
                    change:(NSDictionary*)change 
                   context:(void*)context
{
    if (context == AudioControllerBufferingObservationContext)
    {
        NSLog(@"Buffering status: %@", [object loadedTimeRanges]);
    }
}
Taxiplane answered 12/5, 2012 at 6:51 Comment(6)
Yeah it was the options, I was leaving it set to 0. Thanks!Babul
I tried this solution verbatim. Unfortunately, I get an initial KVO call for loadedTimeRanges that returns an empty NSArray and then nothing.Cavendish
Turns out that the only option that I could get to work for loadedTimeRanges was NSKeyValueObservingOptionInitial. The work around for me was to use a Timer (CADisplayLink actually) to check the loadedTimeRanges property when a UIProgressView was on screen. This works but does seem kludgy to me. I'd rather KVO any new values.Cavendish
I am finding the same as Chris L. Frustratingly, it works the first time, but after I change the player item I get every callback but loadedTimeRangesCirenaica
Robert, the observer is set on the player item, so if you change the player item, you'll have to remove the original observer and add an observer to the new player item.Taxiplane
Same thing happens for me as GnarlyDog and Robert. I can get loadedTimeRanges notifications for my first playerItem but none after that. Same goes for the status key. It's worth noting these playerItems are being used in UITableViewCells.Determiner
S
3

Update to Swift 4.0 and later:

loadedTimeRangesObserver = player.observe(\AVPlayer.currentItem?.loadedTimeRanges, options: [.new, .initial]) { [unowned self] (player, change) in
    DispatchQueue.main.async {    
        guard let ranges = change.newValue as? [CMTimeRange] else { return }
        // update UI
    }
}     
Sympathize answered 25/11, 2020 at 16:33 Comment(0)
N
2

Right. loadedTimeRanges doesn't change but the objects inside of it change. You could setup a timer to run every second (or so) and inspect the values inside of loadedTimeRanges. Then you'll see the changes you are looking for.

dispatch_queue_t queue = dispatch_queue_create("playerQueue", NULL);

[player addPeriodicTimeObserverForInterval:CMTimeMake(1, 1)
                                          queue:queue
                                     usingBlock:^(CMTime time) {  
                                         for (NSValue *time in player.currentItem.loadedTimeRanges) {
                                             CMTimeRange range;
                                             [time getValue:&range];
                                             NSLog(@"loadedTimeRanges: %f, %f", CMTimeGetSeconds(range.start), CMTimeGetSeconds(range.duration));
                                         }
                                     }];
Nosography answered 5/5, 2012 at 18:19 Comment(2)
This won't trigger when AVPlayer paused though.Depurate
@Andy Not sure what you mean. This works perfectly for me. When paused the loadedTimeRanges will stop logging but as soon as you resume they will continue to log and it will be obvious that the values have still been updating while paused.Determiner

© 2022 - 2024 — McMap. All rights reserved.