segundo seguir plano escuchar escuchando como ios background touch avaudioplayer avaudiosession

ios - seguir - youtube en segundo plano apk



iOS-AVAudioPlayer no continúa con la canción siguiente mientras está en segundo plano (3)

Discusión relevante

RESPUESTA CORTA:

Necesitas este código en el método init o viewDidLoad de tu controlador de primera vista:

[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];

LARGA RESPUESTA CON MUESTRA:

Aquí está mi ejemplo. Al igual que usted, comencé con una aplicación que reproducía música de fondo pero que nunca podría seguir reproduciéndose después de que el primer clip terminara. Hice una copia del Music.mp3 original y lo llamé Music2.mp3. Mi intención era reproducir Music2.mp3 tan pronto como Music.mp3 finalizara (audioPlayerDidFinishPlaying :). Estuve jugando un rato con las tareas en segundo plano hasta que conseguí que funcionara SIN la tarea de fondo:

-(id)init{ self = [super initWithNibName:@"MediaPlayerViewController" bundle:nil]; if(self){ //Need this to play background playlist [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; //MUSIC CLIP //Sets up the first song... NSString *musicPath = [[NSBundle mainBundle] pathForResource:@"Music" ofType:@"mp3"]; if(musicPath){ NSURL *musicURL = [NSURL fileURLWithPath:musicPath]; audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:musicURL error:nil]; [audioPlayer setDelegate:self]; } } return self; } -(IBAction)playAudioFile:(id)sender{ if([audioPlayer isPlaying]){ //Stop playing audio and change test of button [audioPlayer stop]; [sender setTitle:@"Play Audio File" forState:UIControlStateNormal]; } else{ //Start playing audio and change text of button so //user can tap to stop playback [audioPlayer play]; [sender setTitle:@"Stop Audio File" forState:UIControlStateNormal]; } } -(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{ [audioButton setTitle:@"Play Audio File" forState:UIControlStateNormal]; [playRecordingButton setTitle:@"Play Rec File" forState:UIControlStateNormal]; //PLAY THE SECOND SONG NSString *musicPath2 = [[NSBundle mainBundle] pathForResource:@"Music2" ofType:@"mp3"]; if(musicPath2){ NSURL *musicURL2 = [NSURL fileURLWithPath:musicPath2]; audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:musicURL2 error:nil]; [audioPlayer setDelegate:self]; NSLog(@"Play it again: /n%@", musicPath2); [audioPlayer play]; } }

El resultado final es que mi aplicación ahora está reproduciendo Music2.mp3 en un bucle continuo, incluso si la aplicación está en segundo plano.

Así que tengo una aplicación que reproduce un montón de canciones, mientras que el usuario puede hojear un cómic. Uso AVAudioPlayer y lo tengo configurado para reproducir las canciones en un orden establecido. Entonces, cuando una canción termina, la siguiente se reproducirá. Esto funciona sin problemas cuando la aplicación está abierta. El problema ocurre cuando la aplicación está en segundo plano. Configuré la aplicación para jugar en segundo plano, y eso funciona bien. Entonces, cuando el usuario presiona la pantalla de inicio, la música continúa sonando. El problema ocurre cuando la canción termina, se supone que debe reproducir la siguiente canción como lo hace cuando la aplicación está abierta. En cambio, nada sucede. De acuerdo con las declaraciones de mi NSLog, se están llamando a los métodos correctos, pero no ocurre nada. Aquí está mi código:

- (void)audioPlayerDidFinishPlaying: (AVAudioPlayer *)player successfully: (BOOL) flag { NSLog(@"Song finished"); if ([songSelect isEqualToString: @"01icecapades"]) { isPlay = @"yes"; songSelect = @"02sugarcube"; imageSelect = @"playbanner02"; [self performSelector:@selector(triggerSong) withObject:nil afterDelay:0]; [self performSelector:@selector(triggerBanner) withObject:nil afterDelay:0]; } else if ([songSelect isEqualToString: @"02sugarcube"]) { isPlay = @"yes"; songSelect = @"03bullets"; imageSelect = @"playbanner03"; [self performSelector:@selector(triggerSong) withObject:nil afterDelay:0]; [self performSelector:@selector(triggerBanner) withObject:nil afterDelay:0]; } else if ([songSelect isEqualToString: @"03bullets"]) { isPlay = @"yes"; songSelect = @"04satanama"; imageSelect = @"playbanner04"; [self performSelector:@selector(triggerSong) withObject:nil afterDelay:0]; [self performSelector:@selector(triggerBanner) withObject:nil afterDelay:0]; } else if ([songSelect isEqualToString: @"04satanama"]) { isPlay = @"yes"; songSelect = @"05uglyjoke"; imageSelect = @"playbanner05"; [self performSelector:@selector(triggerSong) withObject:nil afterDelay:0]; [self performSelector:@selector(triggerBanner) withObject:nil afterDelay:0]; } else if ([songSelect isEqualToString: @"05uglyjoke"]) { isPlay = @"yes"; songSelect = @"01icecapades"; imageSelect = @"playbanner01"; [self performSelector:@selector(triggerSong) withObject:nil afterDelay:0]; [self performSelector:@selector(triggerBanner) withObject:nil afterDelay:0]; }}

Arriba está el código que reconoce qué canción se está reproduciendo y establece la canción correcta a continuación. Luego activa otro método que configura el jugador.

- (void)triggerSong { NSLog(@"triggerSong called"); NSString *path; NSError *error; // Path the audio file path = [[NSBundle mainBundle] pathForResource:songSelect ofType:@"mp3"]; // If we can access the file... if ([[NSFileManager defaultManager] fileExistsAtPath:path]) { // Setup the player player = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error]; //player = [initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error]; [player setDelegate: self]; // Set the volume (range is 0 to 1) player.volume = 1.0f; [player prepareToPlay]; [player setNumberOfLoops:0]; [player play]; NSLog(@"player play"); [error release]; player.delegate = self; // schedules an action every second for countdown [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(updateTimeLeft) userInfo:nil repeats:YES]; }}

Ahora supongo que esta no es la mejor manera de hacerlo, pero funciona muy bien cuando la aplicación está en primer plano. He estado revisando la documentación y parece que no puedo encontrar la causa de este problema. Esperaba que alguien pudiera ver un error en mi enfoque. Como dije antes, se están llamando los dos NSLogs en el método triggerSong, por lo que no puedo ver por qué no se está llamando al jugador AVAudioPlayer.

También tengo la configuración correcta en mi info.plist y tengo esto en mi viewDidLoad:

//Make sure the system follows our playback status [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil]; [[AVAudioSession sharedInstance] setActive: YES error: nil];

Gracias por cualquier idea. Muy apreciado.


Solo para confirmar lo que dijo Squatch, esta también es la solución en Swift:

UIApplication.sharedApplication().beginReceivingRemoteControlEvents()


OS X presenta el mismo problema al usar AVAudioPlayer, sin embargo, UIApplication es una construcción solo para iOS. OS X requiere el uso de NSApplication en su lugar, pero NSApplication no se devuelve hasta que la aplicación finalice, por lo que debemos usar los hilos. Como beneficio adicional, hay un assert () en algún lugar en las profundidades de NSApplication que exige el hilo principal.

Esta función híbrida C ++ / Objective C es una solución para este problema OS X:

void do_the_dumb (void real_application(void)) { std::thread thread ([real_application]() { real_application(); [[NSApplication sharedApplication] terminate: [NSApplication sharedApplication]]; }); [[NSApplication sharedApplication] run]; thread.join(); };