4
votes

This issue has shown up in several other question here on SO:

Slow start for AVAudioPlayer the first time a sound is played

Delay in playing sounds using AVAudioPlayer

I've tried implementing the fixes suggested but none of them are solving my problem. My application presents the user with a grid of objects to touch, when an object is touched a sound is played. This works great except on the initial touch there is a delay of ~2 seconds.

To get around this I initialize my audio player with a dummy aiff file:

- (void)viewDidLoad{
    NSString *soundFile = [Card loadCardSoundPath:@"dummy"];

    AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:
                             [NSURL fileURLWithPath:soundFile] error:nil];
    self.audioPlayer = player;
    [audioPlayer setDelegate:self];
    [audioPlayer prepareToPlay];
//    [audioPlayer play];
    [player release];
...
[super viewDidLoad]; 
}

Then when an object is touched I call:

NSString *soundFile = [Card loadCardSoundPath:name];

if (soundFile != nil){

            AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:
                                     [NSURL fileURLWithPath:soundFile] error:nil];
            self.audioPlayer = player;
            [self.audioPlayer setDelegate:self];
            [self.audioPlayer prepareToPlay];
            [self.audioPlayer play];
            [player release]; 
}

The behavior i'm observing is this: I observe the audio delay when I click the first object if I create a dummy audio player and call prepareToPlay but not play. However if I call play on the dummy audio player then I don't get the delay on the initial object but the view load gets delayed by 2 seconds.

Is there a way to get around this? Should I simply create an NSArray of AVAudioPlayers on load and tell them all to prepare to play, and then just call play when the object is clicked?

1
I ended up creating an NSArray containing AVAudioPlayer objects that have all had prepareToPlay called on them. This works pretty well, although i'm hoping someone will propose a more elegant solution.slayton

1 Answers

4
votes

Sometimes it can help to let viewDidLoad return by spooling off initialization like that using peformSelector:withObject:afterDelay:. For example:

- (void)viewDidLoad{
    // initialization ...
    [super viewDidLoad]; 
    [self performSelector:@selector(primeAudioPlayer) withObject:nil afterDelay:0.1];
}

-(void)primeAudioPlayer {
    NSString *soundFile = [Card loadCardSoundPath:@"dummy"];

    AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:
                             [NSURL fileURLWithPath:soundFile] error:nil];
    [audioPlayer prepareToPlay];
    [player release];
}