2009-05-22 13 views
36

Estoy tratando de eliminar el retraso de inicio cuando se reproduce un archivo de audio (muy corto - menos de 2 segundos) a través de AVAudioPlayer en el iPhone.Inicio lento para AVAudioPlayer la primera vez que se reproduce un sonido

En primer lugar, el código:

NSString *audioFile = [NSString stringWithFormat:@"%@/%@.caf", [[NSBundle mainBundle] resourcePath], @"audiofile"]; 
NSData *audioData = [NSData dataWithContentsOfMappedFile:audioFile]; 

NSError *err; 
AVAudioPlayer *audioPlayer = [(AVAudioPlayer*)[AVAudioPlayer alloc] initWithData:audioData error:&err]; 

audioPlayer.delegate = self; 
[audioPlayer play]; 

también poner en práctica el método audioPlayerDidFinishPlaying para liberar el AVAudioPlayer una vez que he terminado.

La primera vez que reproduzco el audio, el desfase es palpable: al menos 2 segundos. Sin embargo, después de eso, el sonido se reproduce inmediatamente. Sospecho que el culpable, entonces, es el [NSData dataWithContentsOfMappedFile] que lleva mucho tiempo leyendo desde el flash inicialmente, pero luego lo lee rápidamente. Aunque no estoy seguro de cómo probar eso.

¿Es ese el caso? Si es así, ¿debería precachear los objetos NSData y ser agresivo sobre borrarlos en condiciones de poca memoria?

+0

Gracias por la información. Debe responder la pregunta y aceptar su respuesta. La inicialización de AVAudioPlayer al inicio aseguró que el audio se reproducía sin demora en el resto de la aplicación. – brianegge

+1

@johnbiesnecker reproduce cualquier sonido con 0 volumen, luego todas las llamadas de reproducción de sonido deben estar dentro de un bloque de cola global asíncrono, con una prioridad predeterminada o alta, el sonido no se debe reproducir en la cola principal. –

+1

Además de lo que dijo @JuanPabloBoero, también reproduje el sonido de 0 volumen cuando recibo 'UIApplicationWillEnterForegroundNotification'; de lo contrario, hay un retraso después de que la aplicación se reanuda desde el fondo. – Pang

Respuesta

36

El retraso parece estar relacionado con la creación de instancias de AVAudioPlayer por primera vez. Si cargo cualquier audio, ejecuto [audioPlayer prepareToPlay] y luego lo lanzo de inmediato, los tiempos de carga de todos mis otros audios son casi imperceptibles. Así que ahora estoy haciendo eso en applicationDidFinishLaunching y todo lo demás funciona bien.

No puedo encontrar nada al respecto en los documentos, pero ciertamente parece ser el caso.

+1

Hmm, no sé de esto. prepareToPlay no funcionó completamente para mí.El modo "prepareToPlay" funciona, pero como parece que está cargando el audio de forma asíncrona, no hay forma de saber exactamente cuándo el audio está realmente listo para reproducirse. Vea mi respuesta reciente para la solución que se me ocurrió. –

+0

Obtengo un retraso con AVQueuePlayer también cada vez que primero cargo un activo en él. El jugador solo se inicializa una vez. Parece un problema común: http://stackoverflow.com/questions/11171374/how-to-reduce-ios-avplayer-start-delay – Oren

-1

No estoy seguro, pero sospecho que el objeto NSData está siendo flojo y carga el contenido del archivo a pedido. Puede intentar "hacer trampa" llamando al [audioData getBytes:someBuffer length:1]; en algún momento anterior para que cargue ese archivo antes de que sea necesario.

-1

La respuesta es

AVAudioPlayer *audioplayer; 
[audioplayer prepareToPlay]; 
+2

En realidad, [audioplayer prepareToPlay] no es la respuesta ... el retraso I Estaba hablando de que ocurre la primera vez que asigna e inicia un objeto AVAudioPlayer, antes de llamar a cualquiera de sus métodos. Sin embargo, solo ocurre la primera vez que cargas uno. prepareToPlay solo precarga el audio, pero no elimina el retraso que realmente estaba preguntando. Dicho sea de paso, UIWebView exhibe el mismo comportamiento: si asigna y luego libera inmediatamente una, el resto se carga muy rápidamente. –

10

Esto es lo que he hecho (en un hilo separado):

[audioplayer start] 
[audioplayer stop] 
self.audioplayer = audioplayer 

[audioplayer prepareToPlay] parece ser un método asincrónico, por lo que no puede asegúrese de que vuelva si el audio está listo para jugar.

En mi caso llamo a start para que realmente empiece a reproducirse, esto parece ser sincrónico. Entonces lo detengo de inmediato. En el simulador, de todos modos, no escuché ningún sonido que salga de esta actividad. Ahora que el sonido está "realmente" listo para jugar, asigno la variable local a una variable miembro para que el código fuera del hilo tenga acceso a ella.

debo decir que me parece un tanto sorprendente que incluso en iOS 4 se tarda unos 2 segundos justo para cargar un archivo de audio que está a sólo 4 segundos de duración ....

+1

hágalo mientras ve la carga, este es un truco rápido y funciona – yasirmturk

2

que he tomado un enfoque alternativo funciona para mi. He visto esta técnica mencionada en otra parte (aunque no recuerdo en el momento en que fue).

En pocas palabras, compruebe previamente el sistema de sonido cargando y reproduciendo un sonido corto y "en blanco" antes de hacer cualquier otra cosa. El código es el siguiente para un archivo MP3 corta I de la precarga en el método de mi punto de vista del controlador de viewDidLoad que es de 0,1 segundos de duración:

NSError* error = nil; 
    NSString* soundfilePath = [[NSBundle mainBundle] pathForResource:@"point1sec" ofType:@"mp3"]; 
    NSURL* soundfileURL = [NSURL fileURLWithPath:soundfilePath]; 
    AVAudioPlayer* player = [[[AVAudioPlayer alloc] initWithContentsOfURL:soundfileURL error:&error] autorelease]; 
    [player play]; 

Usted puede crear su propio MP3 en blanco si desea, o hacer una búsqueda en Google sobre " mp3s en blanco "para encontrar y descargar uno ya construido por otra persona.

+0

usando esto con NSZombies habilitado revela un mensaje "impl" que se envía al jugador después de dealloc. Lo tengo para evitar esto al no autoreplecionarlo, y en su lugar enviarlo manualmente un mensaje [player release] en el audioPlayerDidFinishPlaying: successfully: event (en callback) – unsynchronized

+0

hasta el último comentario, ver mi respuesta actualizada a esta pregunta para una solución de código fuente: http://stackoverflow.com/a/7426406/830899 – unsynchronized

8

Si el audio es inferior a 30 segundos de duración de largo y está en formato PCM o ima4 lineal, y se empaqueta como un .caf, .wav o .aiff puede utilizar los sonidos del sistema:

la importación Marco AudioToolbox

en su archivo .h crear esta variable:

SystemSoundID mySound; 

en el archivo .m implementarlo en su método init:

-(id)init{ 
if (self) { 
    //Get path of VICTORY.WAV <-- the sound file in your bundle 
    NSString* soundPath = [[NSBundle mainBundle] pathForResource:@"VICTORY" ofType:@"WAV"]; 
    //If the file is in the bundle 
    if (soundPath) { 
     //Create a file URL with this path 
     NSURL* soundURL = [NSURL fileURLWithPath:soundPath]; 

     //Register sound file located at that URL as a system sound 
     OSStatus err = AudioServicesCreateSystemSoundID((CFURLRef)soundURL, &mySound); 

      if (err != kAudioServicesNoError) { 
       NSLog(@"Could not load %@, error code: %ld", soundURL, err); 
      } 
     } 
    } 
return self; 
} 

En el método de IBAction se llama al sonido con este:

AudioServicesPlaySystemSound(mySound); 

Esto funciona para mí, reproduce el sonido muy muy cerca cuando se pulsa el botón. Espero que esto te ayude.

+0

Esta es una gran respuesta. ¡Gracias por publicar esto! –

3

me escribió un simple envoltorio para AVAudioPlayer que proporciona un método prepareToPlay que realmente funciona:

https://github.com/nicklockwood/SoundManager

Es, básicamente, sólo explora su aplicación para archivos de sonido, recoge uno y lo reproduce a un volumen cero. Eso inicializa el hardware de audio y permite que el siguiente sonido se reproduzca al instante.

+0

Lo probé y parece realmente bueno. Gracias ;) – Beny

0

Otra solución consiste en crear un audio silencioso & corto y reproducirlo la primera vez que se inicia el reproductor.

  1. Ajuste el nivel del micrófono a 0 en Preferencias del Sistema.
  2. Abre QuickTime.
  3. Crear nueva grabación de audio (Archivo> Nueva grabación de audio).
  4. Grabar durante 1 o 2 segundos.
  5. Guardar/Exportar el archivo de audio. (tendrá extensión .m4a y aproximadamente 2 kb en tamaño).
  6. Agregue el archivo a su proyecto y reprodúzcalo.

Si no desea crear un nuevo archivo de sonido usted mismo, puede descargar un archivo corto & silencio de audio aquí: https://www.dropbox.com/s/3u45x9v72ic70tk/silent.m4a?dl=0

0

Aquí es una simple extensión Swift a AVAudioPlayer que utiliza el juego-y-parada en 0 idea de volumen presentada en respuestas anteriores. PrepareToPlay() desafortunadamente al menos para mí no funcionó.

extension AVAudioPlayer { 
    private func initDelaylessPlayback() { 
     volume = 0 
     play() 
     stop() 
     volume = 1 
    } 

    convenience init(contentsOfWithoutDelay : URL) throws { 
     try self.init(contentsOf: contentsOfWithoutDelay, fileTypeHint: nil) 
     initDelaylessPlayback() 
    } 
} 
Cuestiones relacionadas