简体   繁体   English

当AVQueuePlayer完成最后一个播放项目时如何做某事

[英]How to do something when AVQueuePlayer finishes the last playeritem

I've got an AVQueuePlayer which I'm creating from an array of 4 AVPlayerItems, and it all plays fine. 我有一个AVQueuePlayer,我是从4个AVPlayerItems的数组创建的,它都可以正常播放。

I want to do something when the last item in the queue finishes playing, I've looked a load of answers on here and this is the one that looks most promising for what I want: The best way to execute code AFTER a sound has finished playing 我希望在队列中的最后一项完成播放时做一些事情,我在这里看了很多答案,这看起来最符合我想要的: 在声音结束后执行代码的最佳方法播放

In my button handler i have this code: 在我的按钮处理程序中,我有这个代码:

static const NSString *ItemStatusContext;

    [thePlayerItemA addObserver:self forKeyPath:@"status" options:0 context:&ItemStatusContext];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(playerItemDidReachEnd)
                                                 name:AVPlayerItemDidPlayToEndTimeNotification
                                               object:thePlayerItemA];

     theQueuePlayer = [AVQueuePlayer playerWithPlayerItem:thePlayerItemA]; 

    [theQueuePlayer play];

and then I have a function to handle playerItemDidReachEnd: 然后我有一个处理playerItemDidReachEnd的函数:

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

But when I run this I get an Internal Inconsistency Exception: 但是当我运行它时,我得到一个内部不一致的例外:

    An -observeValueForKeyPath:ofObject:change:context: message was received but not handled.
Key path: status
Observed object: <AVPlayerItem: 0x735a130, asset = <AVURLAsset: 0x73559c0, URL = file://localhost/Users/mike/Library/Application%20Support/iPhone%20Simulator/5.0/Applications/A0DBEC13-2DA6-4887-B29D-B43A78E173B8/Phonics%2001.app/yes.mp3>>
Change: {
    kind = 1;

} }

What am I doing wrong? 我究竟做错了什么?

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: 这种方法似乎对我有用,在我的按钮处理程序中我有很多东西来为我想要播放的4个mp3文件创建URL,然后:

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: 之后我实现了'playerItemDidReachEnd'选择器,如下所示:

- (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. 这会将4个MP3文件排队,然后当最后一段音频完成时,它会调用选择器并在控制台中显示我的消息。

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) 观察状态不会告诉您项目何时完成播放(它仅告知项目是否为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. 您所要做的就是为playbackQueue中的lastItem注册AVPlayerItemDidPlayToEndTimeNotification 用于初始化您的AVQueuePlayer实例。

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) (注意选择器有playerItemDidReachEnd: ,你忘了两个点)

So then -playerItemDidReachEnd: will only be called exactly once in the end as you need it. 那么-playerItemDidReachEnd:只会在你需要时才调用一次。 (also don't forget to remove yourself as an observer - you can do it in -playerItemDidReachEnd: using notification.object ) (也不要忘记将自己移除为观察者 - 你可以在-playerItemDidReachEnd:使用-playerItemDidReachEnd:使用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: . 不得不说还有其他方法可以做到这一点 :对currentItem使用键值观察,然后在observeValueForKeyPath:检查currentItem是否更改为[NSNull null]

[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 通常对于AVQueuePlayer您将为playbackQueue每个项目注册AVPlayerItemDidPlayToEndTimeNotification ,因此除非您不想在本地存储playbackQueue并使用notification.object-playerItemDidReachEnd:检查其lastObject, -playerItemDidReachEnd:您将使用第二种方式

You likely didn't implement the -observeValueForKeyPath:ofObject:change:context: method in your class. 您可能没有在类中实现-observeValueForKeyPath:ofObject:change:context:方法。 Check out the Apple KVO guide for further details. 查看Apple KVO指南了解更多详情。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM