2009-05-22 5 views
36

Sto cercando di eliminare il ritardo di avvio durante la riproduzione di un file audio (molto breve - meno di 2 secondi) tramite AVAudioPlayer sull'iPhone.Avvio lento per AVAudioPlayer la prima volta che viene riprodotto un suono

In primo luogo, il codice:

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

Ho anche implementare il metodo audioPlayerDidFinishPlaying per rilasciare l'AVAudioPlayer volta che ho fatto.

La prima volta che suono l'audio, il ritardo è palpabile - almeno 2 secondi. Tuttavia, dopo che il suono viene riprodotto immediatamente. Ho il sospetto che il colpevole, quindi, sia il [NSData dataWithContentsOfMappedFile] che impiega molto tempo a leggere dal flash inizialmente, ma poi a essere veloce nelle letture successive. Non sono sicuro di come testarlo, comunque.

È il caso? In tal caso, dovrei solo pre-memorizzare nella cache gli oggetti NSData ed essere aggressivo per eliminarli in condizioni di scarsa memoria?

+0

Grazie per le informazioni. Dovresti rispondere alla domanda e accettare la tua risposta. L'inizializzazione di AVAudioPlayer all'avvio ha assicurato l'audio riprodotto senza ritardo nel resto dell'app. – brianegge

+1

@johnbiesnecker riproduce qualsiasi suono con volume 0, quindi tutte le chiamate di riproduzione audio devono trovarsi all'interno di un blocco di code globali asincrone, con una priorità predefinita o alta, il suono non deve essere riprodotto nella coda principale. –

+1

In aggiunta a ciò che @JuanPabloBoero ha detto, ho anche riprodotto il suono del volume 0 durante la ricezione di 'UIApplicationWillEnterForegroundNotification', altrimenti c'è un ritardo dopo che l'app è stata ripresa dallo sfondo. – Pang

risposta

36

Il ritardo sembra essere correlato all'istanziazione di AVAudioPlayer per la prima volta. Se carico qualsiasi audio, eseguo [audioPlayer prepareToPlay] e poi lo rilascia immediatamente, i tempi di caricamento di tutti i miei altri audio sono molto vicini a impercettibili. Così ora lo sto facendo in applicationDidFinishLaunching e tutto il resto funziona bene.

Non riesco a trovare nulla su questo nei documenti, ma certamente sembra essere il caso.

+1

Hmm, non lo so. prepareToPlay non ha funzionato completamente per me.Preparare una specie di lavoro, ma poiché sembra che il caricamento dell'audio sia asincrono, non c'è modo di sapere esattamente quando l'audio è veramente pronto per essere riprodotto. Vedi la mia recente risposta per la soluzione che ho trovato. –

+0

Ricevo un ritardo anche con AVQueuePlayer ogni volta che carico una risorsa per la prima volta. Il giocatore viene inizializzato solo una volta. Sembra un problema comune: http://stackoverflow.com/questions/11171374/how-to-reduce-ios-avplayer-start-delay – Oren

-1

Non so per certo, ma ho il sospetto che l'oggetto NSData sia pigro e carichi il contenuto del file su richiesta. Puoi provare a "barare" chiamando lo [audioData getBytes:someBuffer length:1]; in qualche momento per farlo caricare prima che sia necessario.

-1

La risposta è

AVAudioPlayer *audioplayer; 
[audioplayer prepareToPlay]; 
+2

In realtà, [audioplayer prepareToPlay] non è la risposta ... il ritardo I stava parlando della prima volta che si assegna e si avvia un oggetto AVAudioPlayer, prima di chiamare uno dei suoi metodi. Tuttavia, accade solo la prima volta che ne carichi uno. prepareToPlay si limita a precaricare l'audio, ma non elimina il ritardo che stavo effettivamente chiedendo. Incidentalmente, UIWebView mostra lo stesso comportamento: se si assegna e quindi si rilascia immediatamente uno, il resto viene caricato molto rapidamente. –

10

Ecco quello che ho fatto (in un thread separato):

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

[audioplayer prepareToPlay] sembra essere un metodo asincrono, quindi non è possibile assicurati che ritorni se l'audio è effettivamente pronto per essere riprodotto.

Nel mio caso chiamo start per iniziare effettivamente a giocare - questo sembra essere sincrono. Quindi lo interrompo immediatamente. Comunque nel simulatore non sento alcun suono proveniente da questa attività. Ora che il suono è "veramente" pronto per essere riprodotto, assegno la variabile locale a una variabile membro in modo che il codice esterno al thread abbia accesso ad essa.

devo dire che mi trovo un po 'sorprendente che anche su iOS 4 ci vogliono circa 2 secondi subito per caricare un file audio che si trova a soli 4 secondi di lunghezza ....

+1

lo fa durante il caricamento della vista, questo è un trucco rapido e funziona con lo – yasirmturk

2

Ho preso un approccio alternativo per me va bene. Ho visto questa tecnica menzionata altrove (anche se non ricordo al momento dove fosse).

In breve, verifica preliminarmente il sistema audio caricando e riproducendo un breve suono "vuoto" prima di fare qualsiasi altra cosa. Il codice è simile al seguente per un breve file mp3 ho precarico nel metodo viewDidLoad di mio controller della vista che è di 0,1 secondi Durata:

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

È possibile creare il proprio mp3 vuoto se si vuole, o di fare una ricerca su google " mp3 vuoti "per trovare e scaricare uno già costruito da qualcun altro.

+0

usando NSZombies abilitato che rivela un messaggio "impl" inviato al giocatore dopo dealloc. l'ho ottenuto per evitare ciò non autoreleggendolo, e invece inviando manualmente un messaggio [rilascio lettore] in audioPlayerDidFinishPlaying: successo: evento (in callback) – unsynchronized

+0

oltre all'ultimo commento, vedere la mia risposta aggiornata a questa domanda per una soluzione di codice sorgente: http://stackoverflow.com/a/7426406/830899 – unsynchronized

8

Se il vostro audio è meno di 30 secondi lunghi di lunghezza ed è in formato PCM o IMA4 lineare, ed è confezionato come un .caf, .wav, o .aiff è possibile utilizzare i suoni di sistema:

Importare il AudioToolbox quadro

nel file .h creare questa variabile:

SystemSoundID mySound; 

nel file .m implementarlo nel metodo 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; 
} 

nel metodo IBAction si chiamano il suono con questo:

AudioServicesPlaySystemSound(mySound); 

Questo funziona per me, riproduce il suono dannatamente vicino alla quando si preme il pulsante. Spero che questo ti aiuti.

+0

Questa è un'ottima risposta. Grazie per aver postato questo! –

3

ho scritto un semplice wrapper per AVAudioPlayer che fornisce un metodo prepareToPlay che funziona davvero:

https://github.com/nicklockwood/SoundManager

E 'fondamentalmente solo analizza la vostra applicazione per i file audio, sceglie uno e lo riproduce a volume zero. Questo inizializza l'hardware audio e consente di riprodurre immediatamente il suono successivo.

+0

Ho appena provato e sembra davvero buono. Grazie ;) – Beny

0

Altra soluzione è creare un breve audio & silenzioso e riprodurlo al primo avvio del lettore.

  1. Imposta il livello del microfono su 0 in Preferenze di Sistema.
  2. Apre QuickTime.
  3. Crea nuova registrazione audio (File> Nuova registrazione audio).
  4. Registra per 1 o 2 secondi.
  5. Salva/Esporta il file audio. (avrà estensione .m4a e circa 2 kb in dimensione).
  6. Aggiungi il file al tuo progetto e riproducilo.

Se non volete creare un nuovo file audio da soli, è possibile scaricare una breve & file audio in silenzio qui: https://www.dropbox.com/s/3u45x9v72ic70tk/silent.m4a?dl=0

0

Ecco una semplice estensione Swift a AVAudioPlayer che utilizza il play-e-sosta a 0 idea del volume presentata nelle risposte precedenti. PrepareToPlay() sfortunatamente almeno per me non ha funzionato.

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

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