What is happening here? cached sound?

Discussion in 'iOS Programming' started by dantastic, Feb 9, 2011.

  1. dantastic macrumors 6502a

    dantastic

    Joined:
    Jan 21, 2011
    #1
    I've a timer and at the end of it an alarm.

    The alarm sits in a function like this:

    Code:
    - (void) soundAlarm {
    	[alarmTimer invalidate];
    	alarmTimer = nil;
    	SystemSoundID sound;
    	AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"ALARM" ofType:@"WAV"]], &sound);
    	AudioServicesPlaySystemSound (sound); 	
    }
    
    The first time the alarm sounds it's off by 0.5 sec or so. Any subsequent call to this function and there is no delay.

    I have tried to put the
    Code:
    AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"ALARM" ofType:@"WAV"]], &sound);
    In the initialization code and just call the PlaySound from my function but the result is the same.

    In the function above though, I'm not retaining anything so I should have to create the sound every time, no?

    I can accept a delay, but why is there no delay the second & 3rd time I sound the alarm?

    Is there any way of making this a bit more consistent? Perhaps playing the sound in the initialization code but in mute, can I do that?
     
  2. nickculbertson macrumors regular

    nickculbertson

    Joined:
    Nov 19, 2010
    Location:
    Nashville, TN
    #2
    The NSTimer has a delay the first time an instance is called. You could do a self performSelector in your viewDidLoad to get that first fire out of the way. There would be a random alarm sound though.

    Where are you firing the timer from? Button? viewDidLoad?

    You could probably do some kind of switch case statement where case 1 is
    Code:
    [alarmTimer invalidate];
    	alarmTimer = nil;
    and all other cases are
    Code:
    SystemSoundID sound;
    	AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"ALARM" ofType:@"WAV"]], &sound);
    	AudioServicesPlaySystemSound (sound); 
    [alarmTimer invalidate];
    	alarmTimer = nil;
    		
     
  3. dantastic thread starter macrumors 6502a

    dantastic

    Joined:
    Jan 21, 2011
    #3
    So it's the timer firing that's causing this.

    I'm firing from a button with this when the button is pressed
    Code:
    alarmTimer = [NSTimer scheduledTimerWithTimeInterval:(countdownSeconds) 
    				target:self selector:@selector(soundAlarm) userInfo:nil repeats:NO];
    
    The first time I press the button there's a 0.5 delay. any subsequent press and there's no delay.

    Could I do a
    Code:
    alarmTimer = [NSTimer scheduledTimerWithTimeInterval:0.0 
    				target:self selector:@selector(doNothingFunction) userInfo:nil repeats:NO];
    
    in my viewDidLoad? you think that would cure the lag? :D
     
  4. nickculbertson macrumors regular

    nickculbertson

    Joined:
    Nov 19, 2010
    Location:
    Nashville, TN
    #4
    Yeah that might work.

    To make sure the timer is the reason for the delay put a NSLog at the end of your timer and see if it shows on the console after a delay.

    If you are firing from a button push IBAction then put the code to play the sound in that method, not at the end of the timer... unless you mean that there is a delay after ( countdownSeconds ) ?

    If the delay is after the countdownSeconds a hacky fix could be...
    Code:
    -(void)viewDidLoad{
        alarmTimer = [NSTimer scheduledTimerWithTimeInterval:.02 
    				target:self selector:@selector(soundAlarm) userInfo:nil repeats:NO];
    }
     -(void)soundAlarm{
       switch(){
         case1://no sound
    break; 
         case2://sound
    break; 
         case3://sound... this could work unless you fire the method a bizillion times 
    break; 
          default:
        break; 
    }
    }
    but I'd try the (doNothingFunction) first.

    Nick
     
  5. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #5
    Yeah, I've experienced something similar with the sound playing a bit delayed the first time. Even if you create the system sound earlier, there seems to be a hitch the first time it's played. Turning down the volume while playing the sound during init seems to be a plausible workaround. You should try it out.
     
  6. dantastic thread starter macrumors 6502a

    dantastic

    Joined:
    Jan 21, 2011
    #6
    I've done some more testing now.

    1) Added some NSLogging. The timer is actually firing accurately enough. It's the sound playing that is delayed the first time.

    2) I did set the timer to fire against a 'doNothing' function in my viewDidLoad but as expected with the result from test 1 that didn't do anything at all.

    I suspect Apple won't be cool about me fiddling with the volume up and down in my app so I need to find a way of playing this without it being played. on the iPhone, is there something like /dev/null I can use to play my sound to or how would I go about playing it?
     
  7. nickculbertson macrumors regular

    nickculbertson

    Joined:
    Nov 19, 2010
    Location:
    Nashville, TN
    #7
    I see.

    The delay occurs the first time with AudioServicesPlaySystemSound. In that case, create a short soundless audio track to play in your viewDidLoad. This will get that first fire out of the way silently. :cool:
     
  8. dantastic thread starter macrumors 6502a

    dantastic

    Joined:
    Jan 21, 2011
    #8
    Aaah! Good thinking 99!

    Code:
    AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"SILENCE" ofType:@"WAV"]], &alarm); 
    	AudioServicesPlaySystemSound (alarm); 
    	AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"ALARM" ofType:@"WAV"]], &alarm);
    
    Playing one sec of silence in the viewDidLoad solved it. sneaky!

    :D
     

Share This Page