Waiting until another sound is finished before playing a new one - cocoa-touch

I am developing an iPhone application that plays sounds. I do not want interrupt or play another sound, if a sound is already playing, regardless of where it was "spawned" from to play. My code is as follows:
if(distance <= 10)
{
NSString *soundPath = [[NSBundle mainBundle] pathForResource:#"sound" ofType:#"wav"];
SystemSoundID soundID;
AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath: soundPath], &soundID);
AudioServicesPlaySystemSound(soundID);
}
Simply, I do not want to play a new sound if one is already playing.
I do not want to queue another sound to play if one is already playing.
Is this possible?

I suggest you use the AVAudioPlayer API rather than AudioServicesPlaySystemSound. It has a delegate which you can use, which defines a method -audioPlayerDidFinishPlaying:successfully: which will tell you when your sound finishes playing. The AVPlayer class also has a -playing method which you can check to see if a sound is currently playing.
So, in other words, do this instead:
NSError *error;
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:soundPath error:&error];
if(!player)
[self doSomethingWithError:error];
[player setDelegate:self];
[player play];

Related

AVAudioPlayer makes system sound louder when played at the same time

I've already asked this question before and even set a bounty but it still remains unanswered. Please someone help me out!!
System sound becomes louder when AVAudioPlayer is initiated
I play sound effects such as button clicking sounds etc with SystemSound and background music with AVAudioPlayer. When AVAudioPlayer starts while SystemSound is being played, that particular system sound becomes like 5 times louder all of a sudden. Has anyone else experienced that? What could be the fix?
These are in SoundControl.m and I'm playing gameBG right after transition.
-(void)gameBG {
self.sharedSoundControl = [SoundControl sharedSoundControl];
if (self.sharedSoundControl.musicOff == NO) {
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[[NSBundle mainBundle] URLForResource:#"bgm" withExtension:#"mp3"] error:nil];
self.audioPlayer.numberOfLoops = -1;
self.audioPlayer.volume = 0.3f;
[self.audioPlayer play];
}}
-(void)transition {
if (self.sharedSoundControl.effectOff == NO) {
NSString *soundPath = [[NSBundle mainBundle] pathForResource:#"transition" ofType:#"caf"];
SystemSoundID soundID;
AudioServicesCreateSystemSoundID((__bridge CFURLRef)[NSURL fileURLWithPath:soundPath], &soundID);
AudioServicesPlaySystemSound(soundID);
}}

iOS not playing my sound?

I've went to COUNTLESS links and tutorials for this, but I either get no errors but no sound plays, or I get an error.
Using the code
NSString *toneFilename = [[NSBundle mainBundle] pathForResource:#"spoken" ofType:#"mp3"];
NSURL *toneURLRef = [NSURL fileURLWithPath:toneFilename];
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL: toneURLRef error: nil];
player.currentTime = 0;
player.volume = 1.0f;
[player play];
My application runs, but doesn't play the sound on load. I was listening to music and tried the app, and it stopped my music as if it were going to play something in-app, but it never did.
Why is this happening?
If you're using ARC, and you declare an AVAudioPlayer as a local variable, the player will be dealloc'ed by ARC before it has a chance to play the sound. To fix the problem, declare the player as a property.

Record Audio/Video with AVCaptureSession and Playback Audio simultaneously?

I'm trying to create an iOS app which can record audio and video while simultaneously outputting audio to the speakers.
To do the recording and preview, I'm using AVCaptureSession, an AVCaptureConnection each for both video and audio, and an AVAssetWriterInput each for both video and audio. I basically achieved this by following the RosyWriter example code.
Prior to setting up recording in this fashion, I was using AVAudioPlayer to play audio.
Now, if I am in the middle of capturing (not even recording, just capturing for preview), and attempt to use AVAudioPlayer, my captureOutput callbacks on my AVCaptureAudioDataOutputSampleBufferDelegate class stop getting called.
Is there a workaround for this?
Is there another, lower level service I should use to be playing audio that won't stop my capture?
mc.
You first set the AVAudioSession and its category. For example in viewDidLoad method,
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionMixWithOthers|AVAudioSessionCategoryOptionDefaultToSpeaker error:nil];
Therefore you can play BGM
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:music_url error:nil];
[self.player setDelegate:self];
[self.player play];
and record the movie
self.captureSession = [[AVCaptureSession alloc] init];
/* ... addInput AVCaptureDeviceInput AVMediaTypeVideo & AVMediaTypeAudio */
/* ... addOutput */
[self.captureSession startRunning];
AVCaptureMovieFileOutput *m_captureFileOutput =[self.captureSession.outputs objectAtIndex:0];
[m_captureFileOutput startRecordingToOutputFileURL:saveMovieURL recordingDelegate:self];

iOS AVAudioPlayer double sound playing issue with Xcode 4.2 and ARC

Ive been beating my head up against the all trying to figure out a weird sound issue in my program. I will post the code below. As a brief description I have a function that gets passed a variable and it takes that and decides which category of sound it should play, within that function I have multiple sounds of reach category so I use an arc4random statement then run that through a switch statement. What keeps happening is that it will play two sounds from the case statement instead of just one, most times if I call it twice with my button push the second time it will play the sound from the first time and a new sound, other times it plays the same same over the top of each other but with a slight delay. I put in a breakpoint in the switch and when it double plays it only goes through the switch once which is really confusing. One thing to note is right before this I do play another sound but it uses a separate AVAudioplayer and path variable so that shouldn't be an issue as it never plays the second sound as the other sound I'm playing. I'm only calling the function once when I press the button so I'm not sure why it does this. I have tried putting the *path and *avaudioplayer variables inside the function but it won't play at all. Searching here it seems as though arc deallocs it before it gets a chance to play it. I ended up trying to put it at the top of my .m file as a global variable then just set the actual path and play the sound within the switch. The sound will play but it plays twice.. Hopefully someone can help me out. I tried putting the avaudioplayer definition as a property as well and it does the same thing. Here is my code snippet. And thanks in advance ...
in the .m file
// Just below my synthesize statements
NSString *path;
AVAudioPlayer *theSound
// My code that I call when the button is pressed
[self playVoice:#"buyVoice"];
// The playVoice function
- (void)playVoice:(NSString*)voiceNum;
if ([voiceNum isEqualToString:#"buyVoice"]) // Bought an Item Time for a voice
{
// play coin sound
[self coinSound];
// play random buy phrase and coin sound
int phraseNumber = 0;
phraseNumber = arc4random() %(3);
switch (phraseNumber)
{
case 0:
{
path = [[NSBundle mainBundle] pathForResource:#"sndBuy1" ofType:#"m4a"];
theSound =[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath: path] error:NULL];
[theSound setNumberOfLoops:0];
[theSound play];
break;
}
case 1:
{
path = [[NSBundle mainBundle] pathForResource:#"sndBuy2" ofType:#"m4a"];
theSound =[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath: path] error:NULL];
[theSound setNumberOfLoops:0];
[theSound play];
break;
}
case 2:
{
path = [[NSBundle mainBundle] pathForResource:#"sndBuy3" ofType:#"m4a"];
theSound =[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath: path] error:NULL];
[theSound setNumberOfLoops:0];
[theSound play];
break;
}
case 3:
{
path = [[NSBundle mainBundle] pathForResource:#"sndBuy4" ofType:#"m4a"];
theSound =[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath: path] error:NULL];
[theSound setNumberOfLoops:0];
[theSound play];
break;
}
}
}
set this code before u play the Audio sound
This will reset the player to the beginning:
[theSound setCurrentTime:0.0];
[theSound play];
try this

AVAudioPlayer Won't Play Repeatedly

I have a relatively simple app that plays a sound using AVAudioPlayer, like this:
NSURL *file3 = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/ball_bounce.aiff", [[NSBundle mainBundle] resourcePath]]];
player3 = [[AVAudioPlayer alloc] initWithContentsOfURL:file3 error:nil];
[player3 prepareToPlay];
to later be called to play, like this:
[player3 play];
But this sound is called in multiple places (collisions with a bouncing ball), many times. Sometimes, the ball hits two things in quick enough succession where the sound from the first bounce is still playing when the ball collides a second time. This second bounce then does not produce a sound. How can I make it play a sound every time it collides, even if it involves paying a sound that overlaps an already playing sound?
Any help is greatly appreciated.
One way to solve this problem would to be create a new instance of AVAudioPlayer if the previous one is already playing:
if([player3 isPlaying]) {
AVAudioPlayer *newPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[player3 url]];
[newPlayer setDelegate:self];
[newPlayer play];
}
Then, in the delegate method audioPlayerDidFinishPlaying:successfully:, you should send the player the -release message:
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
if(player != player3) {
[player release];
}
}
This is just the way it has to be, as you do need a new source buffer for each concurrent sound playing. :(
It is an old thread but maybe someone can benefit from this answer. Creating AVAudioPlayer repeatedly can be a burden for the app and can creates lags. In this case you can use SystemSound.
NSString *pathToMySound = [[NSBundle mainBundle] pathForResource:#"yourMusic" ofType:#"mp3"];
SystemSoundID soundID;
AudioServicesCreateSystemSoundID((__bridge CFURLRef)([NSURL fileURLWithPath: pathToMySound]), &soundID);
AudioServicesPlaySystemSound(soundID);
Downside of this solution, you can't adjust the volume.