Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to know when AVPlayerItem is playing

I am having a problem with AVPlayerItem and AVQueuePlayer. Currently i have a lot of music files which are 1-2 sec long and a queue Player for playing them in sequence.

What I want is to know when a music file has just started playing and not when it has finished playing(via AVPlayerItemDidPlayToEndTimeNotification).

This is because i want to run a function when a new file is loaded and played.

My code:

 for (NSUInteger i = 0; i < [matchedAddr count]; i++)
{
    NSString *firstVideoPath = [[NSBundle mainBundle] pathForResource:[matchedAddr objectAtIndex:i] ofType:@"wav"];
    //NSLog(@"file %@",firstVideoPath);
    avitem=[AVPlayerItem playerItemWithURL:[NSURL fileURLWithPath:firstVideoPath]];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(currentItemIs:)
                                                 name:AVPlayerItemDidPlayToEndTimeNotification
                                               object:avitem];

    [filelist addObject:avitem];
}
 player = [AVQueuePlayer queuePlayerWithItems:filelist];
[player play];


- (void)currentItemIs:(NSNotification *)notification
{
    NSString *asd=[seqArray objectAtIndex:currentColor];
    currentColor=currentColor+1;
    AVPlayerItem *p = [notification object];
    [p seekToTime:kCMTimeZero];

    if([asd isEqual:@"1"])
    {
        [UIView animateWithDuration:0.01 animations:^{
           one.alpha = 0;
        } completion:^(BOOL finished) {

            [UIView animateWithDuration:0.01 animations:^{
               one.alpha = 1;
            }];
        }];
    }
}

As you can see,the currentItemIs void is called but it runs when the track has finished playing.I want to be called when the track is at the beginning.

EDIT: Updated version of Winston's snippet:

NSString * const kStatusKey         = @"status";

        [avitem addObserver:self
                              forKeyPath:kStatusKey
                                 options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
                                 context:@"AVPlayerStatus"];
- (void)observeValueForKeyPath:(NSString *)path
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context {

    if (context == @"AVPlayerStatus") {

        AVPlayerStatus status = [[change objectForKey:NSKeyValueChangeNewKey] integerValue];
        switch (status) {
            case AVPlayerStatusUnknown: {

            }
                break;

            case AVPlayerStatusReadyToPlay: {
                // audio will begin to play now.
                NSLog(@"PLAU");
                [self playa];
            }
                break;
        }
    }
}
like image 678
Theodoros80 Avatar asked Feb 14 '23 04:02

Theodoros80


2 Answers

First you need to register your AVPlayerItem as an observer:

[self.yourPlayerItem addObserver:self
                      forKeyPath:kStatus
                         options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
                         context:AVPlayerStatus];

Then on your player Key Value Observer method you need to check for AVPlayerStatusReadyToPlay status, like so:

- (void)observeValueForKeyPath:(NSString *)path
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context {

     if (context == AVPlayerStatus) {

        AVPlayerStatus status = [[change objectForKey:NSKeyValueChangeNewKey] integerValue];
        switch (status) {
            case AVPlayerStatusUnknown: {

            }
            break;

            case AVPlayerStatusReadyToPlay: {
                // audio will begin to play now.
            }
            break;
   }
}
like image 78
neowinston Avatar answered Feb 16 '23 02:02

neowinston


Following should work:

Observe the Player's State:

let playerItem: AVPlayerItem = AVPlayerItem(asset: videoPlusSubtitles, automaticallyLoadedAssetKeys: requiredAssetKeys)

playerItem.addObserver(self, forKeyPath: #keyPath(AVPlayerItem.status), options: [], context: nil)

player = AVPlayer(playerItem: playerItem)

Respond to a State Change:

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if keyPath == #keyPath(AVPlayerItem.status) {
        let status: AVPlayerItem.Status

        if let statusNumber = change?[.newKey] as? NSNumber {
            status = AVPlayerItem.Status(rawValue: statusNumber.intValue)!
        } else {
            status = .unknown
        }

        // Switch over status value
        switch status {
        case .readyToPlay:
            print("Player item is ready to play.")
            break
        case .failed:
            print("Player item failed. See error")
            break
        case .unknown:
            print("Player item is not yet ready")
            break
        @unknown default:
            fatalError()
        }
    }
}
like image 24
skantus Avatar answered Feb 16 '23 04:02

skantus