12

Estoy tratando de reproducir un MP3 a través de AVAudioPlayer, lo que pensé que era bastante simple. Desafortunadamente, no está funcionando del todo. Aquí está todo lo que hice:AVAudioPlayer deja de jugar inmediatamente con ARC

  • Por el bien de la prueba, he creado una nueva aplicación iOS (Single Vista) en Xcode.
  • añadí el marco AVFoundation al proyecto, así como la #import <AVFoundation/AVFoundation.h> a la ViewController.m

  • he añadido un archivo MP3 a la carpeta de Aplicaciones 'Documentos'.

  • he cambiado el ViewControllersviewDidLoad: a lo siguiente:

Código:

- (void)viewDidLoad 
{ 
    [super viewDidLoad];   

    NSString* recorderFilePath = [NSString stringWithFormat:@"%@/MySound.mp3", [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]];  

    AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:recorderFilePath] error:nil]; 
    audioPlayer.numberOfLoops = 1; 

    [audioPlayer play]; 

    //[NSThread sleepForTimeInterval:20]; 
} 

Por desgracia, el audio se detiene, obviamente, justo después de que comienza la reproducción. Si elimino el comentario sleepForTimeInterval, se reproduce durante 20 segundos y se detiene después. Este problema ocurre solo al compilar con ARC, de lo contrario, funciona sin problemas.

+0

No necesita iniciar otro hilo para reproducir audio. ¿Has intentado proporcionar un puntero de error para ver si se está registrando algo? – isaac

+0

¿Qué error está recibiendo? – Daniel

+0

Sí, pasé un NSError a initWithContensOfURL. Sin embargo, se mantiene nulo ... Así que no tengo ningún error, simplemente deja de jugar de inmediato. – Phlibbo

Respuesta

7

El problema es que al compilar con ARC que necesita para asegurarse de mantener una referencia a los casos que desea mantener viva como el compilador corregir automáticamente "desequilibrada" alloc insertando release llamadas (al menos conceptualmente, leer Mikes Ash blog post for more details) Puede resolver esto asignando la instancia a una propiedad o una variable de instancia.

En caso Phlibbo el código se transformará en:

- (void)viewDidLoad 
{ 
    [super viewDidLoad];   
    NSString* recorderFilePath = [NSString stringWithFormat:@"%@/MySound.mp3", [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]];  
    AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:recorderFilePath] error:nil]; 
    audioPlayer.numberOfLoops = 1; 
    [audioPlayer play]; 
    [audioPlayer release]; // inserted by ARC 
} 

Y el AVAudioPlayer que se deje de jugar inmediatamente, ya que se cancela la asignación cuando se deja ninguna referencia.

No he usado ARC y acabo de leerlo brevemente. Comente mi respuesta si conoce más sobre esto y lo actualizaré con más información.

Más información ARC:
Transitioning to ARC Release Notes
LLVM Automatic Reference Counting

+0

Tienes toda la razón. Como se dijo en los comentarios anteriores. ;) – yinkou

+0

No uso ARC y traté de reproducir sonidos cortos de la misma forma en que escribes. Solo escucho el primer sonido (y da gracias a un error con AVAudioPlayer la primera vez que reproduzco algún sonido). Entonces, en el mejor de los casos, su código corta los primeros segundos de un audio, en el peor, deja de reproducirse antes de que el sonido se detenga solo. – Gargo

+0

@Gargo: Como, Mattias escribe en su publicación, el código explica por qué el jugador no funcionó en mi caso, es intencionalmente defectuoso. Debería consultar un tutorial de AVAudioPlayer, si no tiene experiencia con él. – Phlibbo

3

Uso del AVAudioPlayer como Ivar en el archivo de cabecera con strong:

@property (strong,nonatomic) AVAudioPlayer *audioPlayer 
3

Si necesita múltiples AVAudioPlayers jugando al mismo tiempo, crear un NSMutableDictionary. Establezca la clave como el nombre del archivo. Eliminar del diccionario a través de devolución de llamada de delegado como se muestra a continuación:

-(void)playSound:(NSString*)soundNum { 


    NSString* path = [[NSBundle mainBundle] 
         pathForResource:soundNum ofType:@"m4a"]; 
    NSURL* url = [NSURL fileURLWithPath:path]; 

    NSError *error = nil; 
    AVAudioPlayer *audioPlayer =[[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error]; 

    audioPlayer.delegate = self; 

    if (_dictPlayers == nil) 
     _dictPlayers = [NSMutableDictionary dictionary]; 
    [_dictPlayers setObject:audioPlayer forKey:[[audioPlayer.url path] lastPathComponent]]; 
    [audioPlayer play]; 

} 

-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {   
    [_dictPlayers removeObjectForKey:[[player.url path] lastPathComponent]]; 
} 
+0

Esta es la mejor solución para reproducir sonidos simultáneamente. Si utiliza AVAudioPlayer como una propiedad, el objeto se lanzará cuando reproduzca el siguiente sonido y algunas personas están usando AudioServicesPlaySystemSound, pero Apple está rechazando las aplicaciones porque aún se reproducirá cuando el dispositivo esté silenciado y no haya una API para verificar si el dispositivo está apagado. – Zeeshan