¿No hay delegado de AVPlayer? ¿Cómo rastrear cuando la canción terminó de reproducirse? Desarrollo de iPhone Objective C

84

He mirado a mi alrededor pero no puedo encontrar un protocolo de delegado para AVPlayer class. ¿Lo que da?

Estoy usando su subclase, AVQueuePlayerpara reproducir una matriz de AVPlayerItems, cada uno cargado desde una URL. ¿Hay alguna forma de llamar a un método cuando una canción termina de reproducirse? ¿Notablemente al final de la cola?

Y si eso no es posible, ¿hay alguna forma de que pueda llamar a un método cuando la canción COMIENZA a reproducirse, después del almacenamiento en búfer? Estoy tratando de obtener un ícono de carga allí, pero apaga el ícono antes de que comience la música, a pesar de que es después de la [audioPlayer play]acción.

Tyler
fuente

Respuestas:

152

Sí, la clase AVPlayer no tiene un protocolo delegado como AVAudioPlayer. Debe suscribirse a las notificaciones en un AVPlayerItem. Puede crear un AVPlayerItem utilizando la misma URL que de otro modo pasaría -initWithURL:en 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
fuente
1
Asegúrese de usar itemDidFinishPlaying:, por ejemplo, con dos puntos. De la NSNotificationCenterdocumentación: El método especificado por notificationSelector debe tener uno y solo un argumento (una instancia de NSNotification).
Rudolf Adamkovič
@RudolfAdamkovic Gracias por la nota. Edité mi respuesta en consecuencia.
arexx
8

Si. Agregue un observador de KVO al estado o tasa del jugador:

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

Básicamente, eso es todo.

Descargo de responsabilidad: escribí eso aquí, así que no verifiqué si el código era bueno. TAMBIÉN nunca he usado AVPlayer antes, pero debería estar bien.

Daij-Djan
fuente
¿Cómo eliminar @ "rate" observer?
Saumil Shah
Me dijeron en una edición que tengo que observar la tasa con seguridad. adaptado
Daij-Djan
4
Un problema con este enfoque es que pensará que una pausa es el final de la música. La tasa en la pausa es cero como sería al final.
C6Silver
5

Swift 3 : agrego un observador AVPlayerItemcada vez que agrego un video al reproductor:

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
fuente
1

Hay mucha información en la Guía de programación de AVFoundation de Apple docs (busque la sección de monitoreo de reproducción). Parece ser principalmente a través de KVO, por lo que es posible que desee repasar eso si no está demasiado familiarizado (hay una guía para eso para la Guía de programación de observación de valores clave .

Paul.s
fuente
4
Gracias, primero lo hice funcionar controlando el tiempo a través de KVO, pero luego implementé AVPlayerItemDidPlayToEndTimeNotification ya que es más limpio y menos intensivo en el procesador.
Tyler
1
Una mezcla un poco loca de NSNotificationCenter, KVO y basado en bloques. ¡Decídete Apple!
CupawnTae
1

Estoy usando este y funciona:

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

donde _playingAudioestá mi clase personalizada con algunas propiedades y timeObserveres idivar.

Timur Mustafaev
fuente