Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is KVO on AVPlayerItem.loadedTimeRanges possible?

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?

like image 363
Chris C Avatar asked Jan 25 '12 00:01

Chris C


3 Answers

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]);
    }
}
like image 182
Kevin Avatar answered Nov 10 '22 19:11

Kevin


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));
                                         }
                                     }];
like image 30
SteveB Avatar answered Nov 10 '22 20:11

SteveB


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
    }
}     
like image 2
Bob Chang Avatar answered Nov 10 '22 19:11

Bob Chang