Artem
Artem

Reputation: 939

Proper way of playing sound several times in iOS

I needed to implement playing some .aiff sound 3 times in a row. Sound length is 0.1 ms and intervals between playing should be also 0.1 ms. So I decided to do it with NSTimer. This is my solution:

-(void)playSound{
    timerCounter = 0;
    timerForSound = [NSTimer scheduledTimerWithTimeInterval:0.2
                                                     target:self 
                                                   selector:@selector(playSoundThreeTimes)
                                                   userInfo:nil
                                                    repeats:YES];
}

-(void)playSoundThreeTimes{
    // play alert sound
    AudioServicesPlaySystemSound(beepSound);
    timerCounter++;
    if(timerCounter == 3){ // sound played 3 times
        [timerForSound invalidate];
        timerCounter = 0;
    }
}

The problem is that the sound lags sometimes, even if I set interval 0.25 (0.2 is because sound length + interval = 0.2).

Can anyone suggest a better way to do it or tell what the problem could be caused by.

Artem

Edit: Adding this to asynchronous thread also doesn't work:

dispatch_async(dispatch_get_global_queue(0, 0), ^{
        [self playSound];
    });

Upvotes: 4

Views: 855

Answers (3)

vakio
vakio

Reputation: 3177

Two reasons: 1. NSTimer isn't 100% accurate. 2. You are firing events on the main thread which is where the rest of the UI is.

Like Adam says, you can put it on its own thread. Or maybe use something like CADisplayLink instead of NSTimer.

Edit: If you are right and the culprit is AudioSystemServices... I don't know if it will work but can you try creating 3 different beepSound references and then call beepSound1, beepSound2, beepSound3? Because I think it might be waiting for previous sound to stop. If it doesn't work, I think maybe you need to go with Audio Queue or OpenAL perhaps...

Upvotes: 2

Simone Pistecchia
Simone Pistecchia

Reputation: 2842

Try this:

-(void)playMyAudio {

    //play audio method
    if (loop<3) {   
        [self performSelector:@selector(playAudio) withObject:nil afterDelay:0.1];
        loop++;
    }
    else {
       loop = 0
    }
}

if still lags, the only way i found is to create 3,4 avplayer and play in FIFO mode with AVAudioSession

Upvotes: 0

Adam
Adam

Reputation: 493

I could be wrong, but audio should be on it's own thread, however I'm not sure how to do about it in ObjC (I program audio in c++).

NSTimer is not always going to be accurate as (I think) it's a message thread. At high intervals (1 second+) it's not going to be noticeable, but at such short speeds, it's probably going to lag.

Upvotes: 3

Related Questions