AVAudioPlayer looped sound oddities - ios

I'm using this code to load and begin playing a sound:
- (void) buzz {
if (buzzSound == nil) {
[[AVAudioSession sharedInstance] setActive: YES error: nil];
NSError *error;
NSBundle *mainBundle = [NSBundle mainBundle];
NSURL *soundFile = [[NSURL alloc] initFileURLWithPath: [mainBundle pathForResource: #"buzzer_8"
ofType: #"wav"]];
buzzSound = [[AVAudioPlayer alloc] initWithContentsOfURL: soundFile error: &error];
buzzSound.delegate = self;
if (DEBUG_BLE && error != nil)
printf("Error loading sound: %s\n", [[error localizedDescription] cStringUsingEncoding: NSUTF8StringEncoding]);
}
// Play the sound.
buzzSound.numberOfLoops = -1;
[buzzSound prepareToPlay];
[buzzSound setVolume: 1.0];
if (![buzzSound play]) {
self.buzzSound = nil;
[self buzzSound];
}
}
This code is triggered by a touch down event on a button. When the button gets a touch up event (on or off of the button), it stops the sound with:
[buzzSound stop];
The buzz sound itself is a short .wav file.
The first time buzz is called, the sound plays once. It does not repeat. On subsequent calls it does repeat. Why?
Intermittently, if I play the sound for a short period of time that is about the same length of time as one cycle through the sound file, the sound fails on subsequent calls to buzz, and play returns NO. Thereafter, play will always return NO until the sound is reloaded, after which is plays the sound once as noted above and then starts working correctly until the sound is played for a short time, again.
I do have audioPlayerDecodeErrorDidOccur:error: set up; no error is reported.

Related

How to select and play different audio files with AVAudioPlayer

I am currently using AVAudioPlayer to play an MP3 file when the method is triggered.
This works well however I would now like to add in the ability to select which audio file is played when the method is triggered from a list, this is not going so well.
I have created a UISegmentedControl and attempted to change the AVAudioPlayer method to reflect what has been selected however I am now receiving the following error when the app is launched:
'NSInvalidArgumentException', reason: '*** -[NSURL
initFileURLWithPath:]: nil string parameter'
From what I understand, I am recieving the above error because when the AVAudioPlayer is attempting to initWithContentsOfUrl:, the string being referenced does not contain any data yet, I thought it may have got this from the default segment in the UISegmentedController, however this is not the case.
I have searched for a solution for this but could not find anything which matched what i was attempting to achieve, the closest I could find was to initiate a new session of AVAudioPlayer for every audio file I wanted to play however this seemed very long winded and ultimatly may still not work.
Below is my code so far, if you could suggest how I could make this work, I would appreciate it.
for the UISegmentedController:
- (void) selectTone:(id)sender
{
if (self.alarmToneType == 0) {
self.filePath = [[NSBundle mainBundle] pathForResource: #"alarm" ofType: #"mp3"];
NSLog(#"Tone Selected 0 %#", [HRASettingsViewController alarmToneDescription:(int) self.alarmToneType]);
}
if (self.alarmToneType == 1) {
self.filePath = [[NSBundle mainBundle] pathForResource: #"redalert" ofType: #"mp3"];
NSLog(#"Tone Selected 1 %#", [HRASettingsViewController alarmToneDescription:(int) self.alarmToneType]);
}
if (self.alarmToneType == 2) {
self.filePath = [[NSBundle mainBundle] pathForResource: #"greenalaert" ofType: #"mp3"];
NSLog(#"Tone Selected 2 %#", [HRASettingsViewController alarmToneDescription:(int) self.alarmToneType]);
}
}
I have created the string as a #property above but didn't think you would need that.
for the AVAudioPlayer:
- (void) setupAppAudio {
/////////////////////////////////////////////////////////////////////////////////////
// SOUNDS
// Registers this class as the delegate of the audio session.
[[AVAudioSession sharedInstance] setActive:YES error:nil];
// Use this code instead to allow the app sound to continue to play when the screen is locked.
NSError *sessionError = nil;
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error: &sessionError];
if (sessionError) {
NSLog(#"AVAudioSession ERROR %#", sessionError);
} else {
NSLog(#"AVAudioSession SUCCESSFUL");
}
// Tell other music to be quiet when we are talking!
UInt32 doSetProperty = 1;
AudioSessionSetProperty (kAudioSessionProperty_OtherMixableAudioShouldDuck,
sizeof (doSetProperty),
&doSetProperty);
// Registers the audio route change listener callback function
AudioSessionAddPropertyListener (kAudioSessionProperty_AudioRouteChange,
audioRouteChangeListenerCallback,
(__bridge void *)(self));
NSError *activationError = nil;
[[AVAudioSession sharedInstance] setActive: YES error: &activationError];
// setup
//NSString *filePath;
AVAudioPlayer *newPlayer;
newPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL: [NSURL fileURLWithPath:self.filePath] error: nil];
self.beepPlayer = newPlayer;
// "Preparing to play" attaches to the audio hardware and ensures that playback
// starts quickly when the user taps Play
[self.beepPlayer prepareToPlay];
[self.beepPlayer setVolume: 1.0];
[self.beepPlayer setDelegate: self];
}

Play audio after a Time Interval IOS7

Hi in my application, audio is playing when user press the button but now I have two audio buttons like audio1 and audio2, now I want to play second audio after a time interval once the audio1 is completed by clicking the same button.
- (IBAction)btn1:(id)sender {
NSString *audioPath = [[NSBundle mainBundle] pathForResource:#"audio" ofType:#"mp3" ];
NSURL *audioURL = [NSURL fileURLWithPath:audioPath];
NSError *error;
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioURL error:&error];
[self.audioPlayer play];
}
The above code I have used for play one audio now I want to play second audio once the first audio completed please tell me how to make it.
Thanks.
Try this:
You have to add a bool variable with the name 'firstAudioPlayed' on start the variable should be NO or FALSE.
- (IBAction)btn1:(id)sender {
if (![self.audioPlayer isPlaying]) {
NSString *audioPath;
if (self.firstAudioPlayed) {
audioPath = [[NSBundle mainBundle] pathForResource:#"audio2" ofType:#"mp3" ];
} else {
audioPath = [[NSBundle mainBundle] pathForResource:#"audio1" ofType:#"mp3" ];
}
NSURL *audioURL = [NSURL fileURLWithPath:audioPath];
NSError *error;
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioURL error:&error];
[self.audioPlayer play];
self.firstAudioPlayed = !self.firstAudioPlayed;
}
}
I'm not sure if it's working like this, else just ask with a comment...
Explication of the code:
First you check if the player is already playing a song, if he isn't, you check if the first audio already has played (self.firstAudioPlayed) with this you can give the correct path to load the audio file. Now you play this audio file.
(Sorry for my grammar and my english, corrections are welcome)
You probably should use player's delegate. Set audioPlayer.delegate=self; and implement audioPlayerDidFinishPlaying:successfully: method to see when a player finished playing.
Then you can do whatever you want in there, for example start the second audio.

AVAudioPlayer sound file location not changing / updating

*This is my first stackoverflow question so apologies if I am doing something wrong.
I am trying to create a simple sound board app. I'm having trouble getting my AVAudioPlayer on xCode 4.1 (iOS 6.1.2) to update where the sound file to play is located. I wanted to avoid having multiple audio players (audioPlayer2, audioPlayer3, etc) so I am trying to use the same audio player but instead, update where the sound file is located. I only want one sound playing at a time so multiple sounds is obviously not an issue. Here is my code:
- (IBAction)play {
if (audioPlayer.playing == NO) {
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/k.mp3", [[NSBundle mainBundle] resourcePath]]];
NSError *error;
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
audioPlayer.numberOfLoops = 0;
//I added the next two lines to allow me to play AVAudio with MPiPodPlayer (which I found on this site, too) simultaneously.
AVAudioSession *audiosession = [AVAudioSession sharedInstance];
[audiosession setCategory:AVAudioSessionCategoryAmbient error:nil];
[audioPlayer play];
[start setTitle:#"Stop" forState:UIControlStateNormal];
}
else
if (audioPlayer.playing == YES) {
[audioPlayer stop];
[start setTitle:#"Start" forState:UIControlStateNormal];
}
}
- (IBAction)play2 {
if (audioPlayer.playing == NO) {
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/chicken.mp3", [[NSBundle mainBundle] resourcePath]]];
NSError *error;
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
audioPlayer.numberOfLoops = 0;
AVAudioSession *audiosession = [AVAudioSession sharedInstance];
[audiosession setCategory:AVAudioSessionCategoryAmbient error:nil];
[audioPlayer play];
[start2 setTitle:#"Stop" forState:UIControlStateNormal];
clicked = 1;
clicked2 = 0;
} else
if (audioPlayer.playing == YES) {
[audioPlayer stop];
[start2 setTitle:#"Start" forState:UIControlStateNormal];
clicked = 0;
}
}
My IBActions are linked to UIButtons and the 'start's are UIButton references. Whenever I click on 'start' it plays 'k.mp3' fine, however if I then click on 'start2' AFTER it starts to play the 'k.mp3' file, and not the chicken file. Whichever button I click on first is what the url is set to. This is my first iPhone OS application project so I realize there are probably some embarrassing coding mistakes in there (feel free to correct me). I'd like an answer that would be applicable to multiple buttons, even for some 30 buttons so I do not have to copy and paste stop audio player 1, 2, and 3 for each button.
To summarize: I have multiple buttons that play one sound each, I would like no more than one sound playing at a time; when I click on a button it plays 1 sound and all other audio players stop. I would prefer having only one AVAudioPlayer instance for simplicity. Thanks in advance!
Check if application control goes into - (IBAction)play2
And if control goes in it and it is still not working then you might try [audioPlayer release] before
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
that might do the trick for you

iPodMusicPlayer's bug under ios 6.0.1?

I use [MPMusicPlayerController iPodMusicPlayer] setting the ipod volumn before playing a local "beep.caf" file which use AVAudioPlayer.
Strange things happened, if I kill the system ipod app before running the following code, the beep.caf played just 1~2 second which should be a 30 second audio.
The code like this:
self.ipodPlayer = [MPMusicPlayerController ipodMusicPlayer];
self.ipodPlayer.volumn = .5;
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: fileName];
NSError *err = nil;
self.trackPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:&err];
if(err)
{
//LOG ERR
}
else
{
if ([trackPlayer prepareToPlay]) {
if (![trackPlayer play]) {
//ALog(#"Error:play sound failed.");
}
}
else
{
//ALog(#"Error:prepare play sound failed.");
};
}
This code works well under iOS4.3. I doubt if there is something special done when the iPodMusicPlayer init under iOS 6.0.1.
I need to set ipodPlayer's volumn before play local audio, how can I do this correctly?

Playing sequence of sounds in background with AVAudioPlayer

I want to play sequence of sounds with AVAudioPlayer. All are ok in foreground, but in background I have issues.
After scheduling next sound it plays in background, but initialisation of sound after next fails.
How to resolve this issue?
In fact, I have sequence of sounds and sequence of starting moments. When user touch button application starts play sounds.
I use the following code:
- (void)soundScheduleNext
{
NSURL * url = ...; // get url of next sound file
if (soundPlayer == nil)
soundPlayer = [AVAudioPlayer alloc];
soundPlayer = [soundPlayer initWithContentsOfURL:url error:nil];
soundPlayer.delegate = self;
AVAudioSession * audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
// if this is a first element of sound sequence...
if (soundSeqNext == 0)
{
// ... play right now
[soundPlayer prepareToPlay];
soundStartMoment = [soundPlayer deviceCurrentTime];
[soundPlayer play];
} else {
BOOL prepareToPlayOk = [soundPlayer prepareToPlay];
// when second element of sequence play - prepareToPlayOk is YES; when third - prepareToPlayOk is NO :(
NSLog(#"soundScheduleNext: prepareToPlayOk = %d", (int)prepareToPlayOk, nil);
NSTimeInterval timeMoment = ... ; // get moment of time for next sound
[soundPlayer playAtTime:timeMoment];
}
soundSeqNext++;
}
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
[self soundScheduleNext];
}
audioPlayerDidFinishPlaying function is called every time after end of sound playback finished.
The following line after audio session setting category solves the problem:
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
More info at https://stackoverflow.com/a/8071865/13441

Resources