Нет делегата AVPlayer? Как отследить, когда песня закончилась? Objective C разработка iPhone

84

Я осмотрелся, но не могу найти протокол делегата для AVPlayer class. Что дает?

Я использую его подкласс AVQueuePlayerдля воспроизведения массива AVPlayerItems, каждый из которых загружается из URL. Есть ли способ вызвать метод после окончания воспроизведения песни? Особенно в конце очереди?

И если это невозможно, могу ли я вызвать метод, когда песня НАЧИНАЕТ играть после буферизации? Я пытаюсь вставить значок загрузки, но он отключает значок до того, как музыка фактически начинается, даже если это происходит после [audioPlayer play]действия.

Тайлер
источник

Ответы:

152

Да, у класса AVPlayer нет протокола делегата, такого как AVAudioPlayer. Вам необходимо подписаться на уведомления на AVPlayerItem. Вы можете создать AVPlayerItem, используя тот же URL-адрес, который вы в противном случае -initWithURL:передали бы в AVPlayer.

-(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
}
arexx
источник
1
Обязательно используйте itemDidFinishPlaying:, например, с двоеточием. Из NSNotificationCenterдокументации: метод, указанный в notificationSelector, должен иметь один и только один аргумент (экземпляр NSNotification).
Рудольф Адамкович
@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, но все должно быть правильно.

Дайдж-Джан
источник
Как удалить @ "рейтинг" наблюдателя?
Saumil Shah
В редакции мне сказали, что мне нужно обязательно следить за скоростью. адаптировано
Дайдж-Джан
4
Проблема с этим подходом в том, что он будет думать, что пауза - это конец музыки. Ставка на паузе равна нулю, как и в конце.
C6Silver
5

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
}
budiDino
источник
1

В документации Apple по программированию AVFoundation содержится много информации (ищите раздел мониторинга воспроизведения). Похоже, что в основном это происходит через KVO, поэтому вы можете освежить его в памяти, если вы не слишком знакомы (для этого есть руководство в Руководстве по программированию наблюдения за ключевыми значениями .

Paul.s
источник
4
Спасибо, сначала я заставил его работать, отслеживая время через KVO, но затем я реализовал AVPlayerItemDidPlayToEndTimeNotification, так как он чище и менее загружает процессор.
Tyler
1
Немного сумасшедшего сочетания NSNotificationCenter, KVO и блочного. Решайся, Apple!
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мой пользовательский класс с некоторыми свойствами и timeObserverявляется idИвар.

Тимур Мустафаев
источник