How to do something when AVQueuePlayer finishes the last playeritem

北战南征 提交于 2019-12-05 06:18:46

This approach seems to work for me, within my button handler i've got a bunch of stuff to create URLs for the 4 mp3 files I want to play, then:

AVPlayerItem *thePlayerItemA = [[AVPlayerItem alloc] initWithURL:urlA];
AVPlayerItem *thePlayerItemB = [[AVPlayerItem alloc] initWithURL:urlB];
AVPlayerItem *thePlayerItemC = [[AVPlayerItem alloc] initWithURL:urlC];    
AVPlayerItem *thePlayerItemD = [[AVPlayerItem alloc] initWithURL:urlD];  

NSArray *theItems = [NSArray arrayWithObjects:thePlayerItemA, thePlayerItemB, thePlayerItemC, thePlayerItemD, nil];
theQueuePlayer = [AVQueuePlayer queuePlayerWithItems:theItems];

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(playerItemDidReachEnd:)
                                             name:AVPlayerItemDidPlayToEndTimeNotification
                                           object:[theItems lastObject]];
[theQueuePlayer play];

After which I have implement the 'playerItemDidReachEnd' selector like this:

- (void)playerItemDidReachEnd:(NSNotification *)notification {
    // Do stuff here
    NSLog(@"IT REACHED THE END");
}

This queues up the 4 MP3 files and then when the last piece of audio has finished it calls the selector and my message appears in the console.

I hope that this is useful for someone else.

Observing for status will not tell you when item is finished playing(it only tells when item is readyToPlay)

All you have to do it is to register for AVPlayerItemDidPlayToEndTimeNotification for the lastItem in your playbackQueue, which use to initialise your AVQueuePlayer instance.

AVQueuePlayer* player = [AVQueuePlayer queuePlayerWithItems:currentPlaybackQueue];
[[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(playerItemDidReachEnd:)
                                                 name:AVPlayerItemDidPlayToEndTimeNotification
                                               object:currentPlaybackQueue.lastObject];

(note that selector has playerItemDidReachEnd:, you forgot two dots)

So then -playerItemDidReachEnd: will only be called exactly once in the end as you need it. (also don't forget to remove yourself as an observer - you can do it in -playerItemDidReachEnd: using notification.object)

Have to say that there is other way to do this: Using key-value observing for currentItem, then checking if the currentItem changed to [NSNull null] in observeValueForKeyPath:.

[player addObserver:self forKeyPath:@"currentItem" options:NSKeyValueObservingOptionNew context:nil];

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"currentItem"]) {

        if (change[NSKeyValueChangeNewKey] == [NSNull null]) {
            //last item finished playing - do something

        }
    }
}

normally for AVQueuePlayer you will register for AVPlayerItemDidPlayToEndTimeNotification for each item in playbackQueue, so unless you don't want to store playbackQueue locally and check its lastObject with notification.object in -playerItemDidReachEnd:, you would use the second way

You likely didn't implement the -observeValueForKeyPath:ofObject:change:context: method in your class. Check out the Apple KVO guide for further details.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!