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?
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]);
}
}
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));
}
}];
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
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With