Nie masz delegata AVPlayera? Jak śledzić, kiedy piosenka się skończyła? Cel rozwoju C iPhone'a

84

Rozejrzałem się, ale nie mogę znaleźć protokołu delegata dla AVPlayer class. Co daje?

Używam jego podklasy, AVQueuePlayeraby odtworzyć tablicę, z AVPlayerItemsktórych każda jest ładowana z adresu URL. Czy istnieje sposób, w jaki mogę wywołać metodę, gdy piosenka zakończy się odtwarzać? Zwłaszcza na końcu kolejki?

A jeśli to niemożliwe, czy jest jakiś sposób, abym mógł wywołać metodę, gdy piosenka ZACZYNA SIĘ odtwarzać po buforowaniu? Próbuję umieścić tam ikonę ładowania, ale wyłącza ją przed rozpoczęciem odtwarzania muzyki, nawet jeśli jest po [audioPlayer play]akcji.

Tyler
źródło

Odpowiedzi:

152

Tak, klasa AVPlayer nie ma protokołu delegata, takiego jak AVAudioPlayer. Musisz zasubskrybować powiadomienia w AVPlayerItem. Możesz utworzyć AVPlayerItem przy użyciu tego samego adresu URL, do którego w innym przypadku zostałbyś przekazany -initWithURL:w 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
źródło
1
Pamiętaj, aby użyć itemDidFinishPlaying:, np. Z okrężnicą. Z NSNotificationCenterdokumentacji: Metoda określona przez notificationSelector musi mieć jeden i tylko jeden argument (wystąpienie NSNotification).
Rudolf Adamkovič
@RudolfAdamkovic Dzięki za notatkę - odpowiednio zredagowałem moją odpowiedź.
arexx
8

Tak. Dodaj obserwatora KVO do statusu lub stawki gracza:

- (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...];
}

Więc w zasadzie to wszystko.

Zastrzeżenie: napisałem to tutaj, więc nie sprawdziłem, czy kod jest dobry. TAKŻE nigdy wcześniej nie używałem AVPlayera, ale powinno być dobrze.

Daij-Djan
źródło
Jak usunąć obserwatora @ "rate"?
Saumil Shah
W edycji powiedziano mi, że na pewno muszę obserwować kurs. dostosowany
Daij-Djan,
4
Problem z tym podejściem polega na tym, że przerwa będzie oznaczała koniec muzyki. Stawka podczas pauzy wynosi zero, tak jak na końcu.
C6Silver
5

Swift 3 - dodaję obserwatora za AVPlayerItemkażdym razem, gdy dodaję wideo do odtwarzacza:

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
źródło
1

Wiele informacji można znaleźć w Przewodniku programowania AVFoundation firmy Apple (poszukaj sekcji odtwarzania monitorowania). Wydaje się, że odbywa się to głównie przez KVO, więc możesz chcieć odświeżyć to, jeśli nie jesteś zbyt zaznajomiony (istnieje przewodnik po tym, jak Key Value Observing ProgrammingGuide) .

Paul.s
źródło
4
Dzięki, najpierw uruchomiłem go, monitorując czas przez KVO, ale potem zaimplementowałem AVPlayerItemDidPlayToEndTimeNotification, ponieważ jest czystszy i mniej obciążający procesor.
Tyler
1
Trochę szalonej mieszanki NSNotificationCenter, KVO i bloków. Podejmij decyzję Apple!
CupawnTae
1

Używam tego i działa:

_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];

gdzie _playingAudiojest moja niestandardowa klasa z niektórymi właściwościami i timeObserverjest idivar.

Timur Mustafaev
źródło