How to tell that AVAudioPlayer has finished playing - ios

I'm developing an app that plays sounds using AVAudioPlayer, and I want to know when a sound has finished playing. I want to change an image when the sound stops playing
Here's the code I use to create the player:
NSURL* url = [[NSBundle mainBundle] URLForResource:#"LOLManFace1" withExtension:#"mp3"];
NSAssert(url, #"URL is valid.");
NSError* error = nil;
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&url];error;
if(!self.player)
{
NSLog(#"Error creating player: %#", error);
}
And here's the code I use to play the sound:
[self.player play];
How can I tell that playback has finished?
Thank you so much in advance!

Look at the AVAudioPlayerDelegate protocol which has a method to tell the delegate when audio playback has finished among other things, specifically what you are looking for is - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag, here is a reference
Hope it helps
Daniel

Long time ago and I am pretty sure you figured out at one point. If someone reads this post:
1) Your class should implement the AVAudioPlayerDelegate. (https://developer.apple.com/documentation/avfoundation/avaudioplayerdelegate)
One of the delegate methods is:
audioPlayerDidFinishPlaying:successfully:
2) Set delegate:
self.player.delegate = self

Related

How to mute a audio sound when an action is tapped?

Adcolony is a video advert platform integrated into Xcode to play ads to users in video and sound,
One of the requirements is to block audio when the add starts playing,
This is the audio:
//Audio Sound On - uncomment
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:#"soundTrack"
ofType:#"mp3"]];
audioPlayer = [[AVAudioPlayer alloc]
initWithContentsOfURL:url
error:nil];
it starts as soon as the game starts, in view controller,
The triggerVideo action is place in PlayViewController and needs to be set off when ad is triggered,
- (IBAction)TriggerVideo:(id)sender {
[AdColony playVideoAdForZone:#"ZONE-NUMBER-HERE" withDelegate:nil];
}
I've left this aside for a while now, wondering if anyone knows how to employ this function?
add these methods to your viewController that's the delegate for adcolony, which should also be the viewcontroller in which you initialize the AVAudioPlayer. I probably don't need to state this, but i'm assuming you have an #Property for your audioPlayer
- (void) onAdColonyAdStartedInZone:(NSString *)zoneID{
self.audioPlayer.volume = 0.0f;
}
- (void) onAdColonyAdAttemptFinished:(BOOL)shown inZone:(NSString *)zoneID{
self.audioPlayer.volume = 1.0f;
}

play 15 second mp3 ios

I have tried everything I can find to try and get my app to play an mp3. I have a few 2-3 second mp3s that play as sound effects that work, but I am trying to play a 15s mp3 without any luck.
NSError *error;
AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[[NSBundle mainBundle] URLForResource: #"test" withExtension: #"mp3"] error:&error];
if (error) {
NSLog(#"Error creating audio player: %#", [error userInfo]);
} else {
if([audioPlayer play] == FALSE) {
NSLog(#"Fail %#", error);
}
}
NSTimer* myTimer = [NSTimer scheduledTimerWithTimeInterval: 15.0 target: self
selector: #selector(stopMusic) userInfo: nil repeats: NO];
I doubt the timer has anything to do with it but thought I would include it just in case. Basically my error checks are not getting triggered at all. It "should" be playing properly but no sound is coming out, and no errors are being displayed.
I have tried a few other things to try and get this working, and I have tried without the timer. I can't find a decent guide. I don't need a full blown media player, just some background music for an UIScreenViewController.
I have also tried the following code, which works good with short MP3s, not with the longer MP3 I want to play.
NSString *path = [[NSBundle mainBundle] pathForResource:#"bgmusic" ofType:#"mp3"];
NSURL *pathURL = [NSURL fileURLWithPath : path];
AudioServicesCreateSystemSoundID((__bridge CFURLRef)pathURL, &audioEffect);
AudioServicesPlaySystemSound(audioEffect);
Please help, I have spent hours trying to sort this. It seems apple re-jig their audio every time they release an OS.
I did a little testing for you: It turned out that music files aren't added to target by default in Xcode 5. Therefore URLForResource:error: likely returns nil.
Try removing the mp3 from your project. Then add it again and this time make shure you add it to your target:
The other thing is: It seems like you're defining the AVAudioPlayer inside a method. You normally set up a #property for your audio player because otherwise its life is limited to the method - and the music stops playing after you reach the end of the method.

AudioServicesPlaySystemSound not playing except when I step over

I'm writing an alarm clock app and I need to have the user select the chime to wake up to. I have a UITableView with a list of my sounds and when the user taps a sound I want it to play.
However, my sounds do not play unless I step over the call to AudioServicesPlaySystemSound (or if I put a breakpoint on the call to AudioServicesDisposeSystemSoundID which triggers after I hear the sound).
I had a theory that this was a main thread issue so I used performSelectorOnMainThread:
[self performSelectorOnMainThread:#selector(playWakeUpSound)
withObject:nil
waitUntilDone:true];
but that didn't help. (The value of waitUntilDone doesn't seem to matter.)
This question was promising but I checked and I'm only calling my method once.
This is only a guess, since I don't know what is in playWakeUpSound. If you are using AVAudioPlayer within that call and ARC, it might be because it is getting released. Store the instance of AVAudioPlayer as a member of the class and it should play.
#interface MyClass
{
AVAudioPlayer *player;
}
#end
Then in the implementation:
#implementation MyClass
- (void)playWakeUpSound {
// Assuming name and extension is set somewhere.
NSURL* musicFile = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:name ofType:extension]];
NSError* error = nil;
player = [[AVAudioPlayer alloc] initWithContentsOfURL:musicFile error:&error];
if (error) {
NSLog(#"%#", error.localizedDescription);
} else {
[player play];
}
}
#end

Play multiple sounds (one by one) with AVAudioPlayer

I am using AVAudioPlayer to make an MP3 player. I have multiple MP3 sounds and would like to play these sounds one by one. Following is the logic of my app:
///// For playing 1st sound
mp3Player = [[AVAudioPlayer alloc] initWithContentsOfURL:url1 error:nil];
[mp3Player prepareToPlay];
[mp3Player play];
///// For playing 2nd sound
mp3Player = nil;
mp3Player = [[AVAudioPlayer alloc] initWithContentsOfURL:url2 error:nil];
[mp3Player prepareToPlay];
[mp3Player play];
///// For playing 3rd sound
mp3Player = nil;
mp3Player = [[AVAudioPlayer alloc] initWithContentsOfURL:url3 error:nil];
[mp3Player prepareToPlay];
[mp3Player play];
etc...
Just would like to know: I nil out the player and alloc AVAudioPlayer before playing the next sound. Is there any performance (speed) or memory (leak) concern in this logic? (I am using ARC). If so, is there any way to alloc AVAudioPlayer just ONE time, and to accept diffrent URLs pointing to those sounds? Thanks a lot in advance.
I think below link may help you:
How to play multiple audio files in sequence by loop in AVAudioPlayer?
In which audioPlayerDidFinishPlaying is used to play next song after one finishes.

iPhone AVAudioPlayer app freeze on first play

I'm using AVAudioPlayer from iOS SDK for playing short sounds on each click in tableView rows.
I have manually made #selector on button in each row that fires up method playSound:(id)receiver {}. From receiver I get sound url so I can play it up.
This method looks like that:
- (void)playSound:(id)sender {
[audioPlayer prepareToPlay];
UIButton *audioButton = (UIButton *)sender;
[audioButton setImage:[UIImage imageNamed:#"sound_preview.png"] forState:UIControlStateNormal];
NSString *soundUrl = [[listOfItems objectForKey:[NSString stringWithFormat:#"%i",currentPlayingIndex]] objectForKey:#"sound_url"];
//here I get mp3 file from http url via NSRequest in NSData
NSData *soundData = [sharedAppSettingsController getSoundUrl:defaultDictionaryID uri:soundUrl];
NSError *error;
audioPlayer = [[AVAudioPlayer alloc] initWithData:soundData error:&error];
audioPlayer.numberOfLoops = 0;
if (error) {
NSLog(#"Error: %#",[error description]);
}
else {
audioPlayer.delegate = self;
[audioPlayer play];
}
}
Everything works fine except for the first play of some sound. The application freezes for about 2 seconds and than sound is played. Second and every other sound play works just right after click on sound button.
I wonder why there is that about 2 seconds freeze on first play when application starts?
From your code snippet, audioPlayer must be an ivar, right?
At the top of the method, you invoke -prepareToPlay on the existing audioPlayer instance (which could be nil, at least on the first pass).
Later in the method, you replace this existing audio player with a brand new AVAudioPlayer instance. The previous -prepareToPlay is wasted. And you're leaking memory with each new AVAudioPlayer.
Instead of caching sound data or URLs, I would try creating a cache of AVAudioPlayer objects, one for each sound. In your -playSound: method, get a reference to the appropriate audio player for the table row, and -play.
You can use -tableView:cellForRowAtIndexPath: as the appropriate point to get the AVAudioPlayer instance for that row, maybe lazily creating the instance and caching it there as well.
You can try -tableView:willDisplayCell:forRowAtIndexPath: as the point where you would invoke -prepareToPlay on the row's AVAudioPlayer instance.
Or you could just do the prepare in -tableView:cellForRowAtIndexPath:. Experiment and see which works best.
Check whether you are getting data asynchronously in function..
NSData *soundData = [sharedAppSettingsController getSoundUrl:defaultDictionaryID uri:soundUrl];
If you are getting asynchronously the execution will be blocked until it will get data.
If your audio is less than 30 seconds long in length and is in linear PCM or IMA4 format, and is packaged as a .caf, .wav, or .aiff you can use system sounds:
Import the AudioToolbox Framework
In your .h file create this variable:
SystemSoundID mySound;
In your .m file implement it in your init method:
-(id)init{
if (self) {
//Get path of VICTORY.WAV <-- the sound file in your bundle
NSString* soundPath = [[NSBundle mainBundle] pathForResource:#"VICTORY" ofType:#"WAV"];
//If the file is in the bundle
if (soundPath) {
//Create a file URL with this path
NSURL* soundURL = [NSURL fileURLWithPath:soundPath];
//Register sound file located at that URL as a system sound
OSStatus err = AudioServicesCreateSystemSoundID((CFURLRef)soundURL, &mySound);
if (err != kAudioServicesNoError) {
NSLog(#"Could not load %#, error code: %ld", soundURL, err);
}
}
}
return self;
}
In your IBAction method you call the sound with this:
AudioServicesPlaySystemSound(mySound);
This works for me, plays the sound pretty damn close to when the button is pressed. Hope this helps you.
This sometimes happens in the simulator for me too. Everything seems to work fine on the device. Have you tested on actual hardware?

Resources