I\'m trying to eliminate startup lag when playing a (very short -- less than 2 seconds) audio file via AVAudioPlayer on the iPhone.
First, the code:
I wrote a simple wrapper for AVAudioPlayer that provides a prepareToPlay method that actually works:
https://github.com/nicklockwood/SoundManager
It basically just scans your app for sound files, picks one and plays it at zero volume. That initialises the audio hardware and allows the next sound to play instantly.
The delay seems to be related to instantiating AVAudioPlayer for the first time. If I load any audio, run [audioPlayer prepareToPlay] and then immediately release it, the load times for all of my other audio is very close to imperceptible. So now I'm doing that in applicationDidFinishLaunching and everything else runs well.
I can't find anything about this in the docs, but it certainly seems to be the case.
The answer is
AVAudioPlayer *audioplayer;
[audioplayer prepareToPlay];
I don't know for sure, but I suspect the NSData object is being lazy and loading the contents of the file on demand. You can try "cheating" by calling [audioData getBytes:someBuffer length:1];
at some early point to get it to load that file before it's needed.
If your audio is less than 30 seconds long in length and is in linear PCM or IMA4 format, and is packaged as a .caf, .wav, or .aiff you can use system sounds:
Import the AudioToolbox Framework
In your .h file create this variable:
SystemSoundID mySound;
In your .m file implement it in your init method:
-(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;
}
In your IBAction method you call the sound with this:
AudioServicesPlaySystemSound(mySound);
This works for me, plays the sound pretty damn close to when the button is pressed. Hope this helps you.
Other workaround is to create a short & silent audio and play it on the first time player is initiated.
If you dont want to create a new sound file yourself, you may download a short & silent audio file here : https://www.dropbox.com/s/3u45x9v72ic70tk/silent.m4a?dl=0