没有AVPlayer代理?如何跟踪歌曲何时播放完毕?Objective-C iPhone开发。

91

我找了一圈,但是我找不到 AVPlayer class 的委托协议。这是怎么回事?

我正在使用它的子类 AVQueuePlayer,播放从URL加载的AVPlayerItems数组。是否有任何方式可以在歌曲播放完成时调用方法?特别是在队列末尾?

如果不可能,那么是否有任何办法可以在缓冲后歌曲开始播放时调用方法?我试图在那里加入一个加载图标,但即使在 [audioPlayer play] 操作之后,它也会在音乐实际开始之前关闭图标。

5个回答

156

是的,AVPlayer类没有像AVAudioPlayer一样的委托协议。您需要订阅AVPlayerItem上的通知。您可以使用与在AVPlayer上通过-initWithURL:传递的相同URL创建AVPlayerItem。

-(void)startPlaybackForItemWithURL:(NSURL*)url {

    // First create an AVPlayerItem
    AVPlayerItem* playerItem = [AVPlayerItem playerItemWithURL:url];

    // Subscribe to the AVPlayerItem's DidPlayToEndTime notification.
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(itemDidFinishPlaying:) name:AVPlayerItemDidPlayToEndTimeNotification object:playerItem];

    // Pass the AVPlayerItem to a new player
    AVPlayer* player = [[[AVPlayer alloc] initWithPlayerItem:playerItem] autorelease];

    // Begin playback
    [player play]

} 

-(void)itemDidFinishPlaying:(NSNotification *) notification {
    // Will be called when AVPlayer finishes playing playerItem
}

1
请确保使用itemDidFinishPlaying:,例如带有冒号。根据NSNotificationCenter文档:通知选择器指定的方法必须有且仅有一个参数(一个NSNotification实例)。 - Rudolf Adamkovič
@RudolfAdamkovic 感谢您的提醒 - 我已相应地编辑了我的答案。 - arexx

8
是的。将一个KVO观察者添加到播放器的状态或速率中:
- (IBAction)go {
   self.player = .....
   self.player.actionAtItemEnd = AVPlayerActionStop;
   [self.player addObserver:self forKeyPath:@"rate" options:0 context:0]; 
}

- (void)stopped {
    ...
    [self.player removeObserver:self]; //assumes we are the only observer
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if (context == 0) {
        if(player.rate==0.0) //stopped
            [self stopped];
    }
    else
        [super observeVal...];
}

基本上就是这样。

免责声明:我在这里写了这个,所以我没有检查代码是否正确。而且我以前从未使用过AVPlayer,但应该差不多。


如何移除@"rate"观察者? - Saumil Shah
我被告知在编辑中一定要观察速率。 - Daij-Djan
4
这种方法的问题在于它会认为暂停是音乐结束了。暂停时的速率为零,就像结束时一样。 - C6Silver

6

Swift 3 - 每次将视频添加到播放器时,我都会向AVPlayerItem添加一个观察者:

func playVideo(url: URL) {
  let playerItem = AVPlayerItem(asset: AVURLAsset(url: someVideoUrl))
  NotificationCenter.default.addObserver(self, selector: #selector(playerItemDidPlayToEndTime), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: playerItem)
  self.player.replaceCurrentItem(with: playerItem)
  self.player.play()
}

func playerItemDidPlayToEndTime() {
  // load next video or something
}

1

4
谢谢,首先我通过KVO监控时间,让它工作了,但后来我实现了AVPlayerItemDidPlayToEndTimeNotification,因为它更加简洁和少占用处理器资源。 - Tyler
1
有点疯狂的混合了NSNotificationCenter、KVO和基于块的东西。下定决心吧,苹果! - CupawnTae

1
我正在使用这个,它有效:

_player = [[AVPlayer alloc]initWithURL:[NSURL URLWithString:_playingAudio.url]];
CMTime endTime = CMTimeMakeWithSeconds(_playingAudio.duration, 1);
timeObserver = [_player addBoundaryTimeObserverForTimes:[NSArray arrayWithObject:[NSValue valueWithCMTime:endTime]] queue:NULL usingBlock:^(void) {
    [_player removeTimeObserver:timeObserver];
    timeObserver = nil;
    //TODO play next sound
}];
[self play];

其中_playingAudio是我的自定义类,具有一些属性,timeObserverid实例变量。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接