Do an action when a sound has finished playing in AVAudioPlayer?
Solution 1
When a sound is finished playing, I want the application to do something.
Then set yourself as the delegate and respond to audioPlayerDidFinishPlaying:successfully:
.
In the code snippet you showed, you've done step 2 but not step 1: You're not setting yourself as the delegate.
I tried to use
applicationDidFinishLaunching
to do the action at the end of the first sound …
Brain fart? That method has nothing that I can see to do with playing sounds.
…, but I couldn't use that for the second sound because I got a redefinition error.
Huh? Did you implement the method twice or something instead of just comparing the player object in the method body?
It would help if you showed the exact error message you got.
Solution 2
Swift 3:
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
print("sound file finished")
}
Related videos on Youtube
Comments
-
Evelyn over 3 years
I am using the AVAudioPlayer framework, and I have several sounds that play one at a time. When a sound is finished playing, I want the application to do something. I tried to use audioPlayerDidFinishPlaying to do the action at the end of the first sound, but I couldn't use that for the second sound because I got a redefinition error. Can I use NSTimeInterval to get the duration of a sound?
// ViewController.h #import <UIKit/UIKit.h> #import <AVFoundation/AVFoundation.h> #import <AVFoundation/AVAudioPlayer.h> @interface ViewController : UIViewController { UIButton *begin; UIWindow *firstTestWindow; UIWindow *secondTestWindow; AVAudioPlayer *player; NSTimeInterval duration; } @property (nonatomic, retain) IBOutlet UIButton *begin; @property (nonatomic, retain) IBOutlet UIWindow *firstTestWindow; @property (nonatomic, retain) IBOutlet UIWindow *secondTestWindow; @property (nonatomic, retain) AVAudioPlayer *player; @property (readonly) NSTimeInterval duration; - (IBAction)begin:(id)sender; - (IBAction)doTapScreen:(id)sender; @end //ViewController.m #import "ViewController.h" @implementation ViewController @synthesize begin, player, firstTestWindow, secondTestWindow; //first sound - (IBAction)begin:(id)sender; { [firstTestWindow makeKeyAndVisible]; NSString *soundFilePath = [[NSBundle mainBundle] pathForResource: @"Tone1" ofType: @"mp3"]; NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: soundFilePath]; AVAudioPlayer *newPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL: fileURL error: nil]; [fileURL release]; self.player = newPlayer; [newPlayer release]; [player prepareToPlay]; [self.player play]; } //If user does not do anything by the end of the sound go to secondWindow - (void) audioPlayerDidFinishPlaying: (AVAudioPlayer *) player successfully: (BOOL) flag { if (flag==YES) { [secondWindow makeKeyAndVisible]; } } //second sound - (IBAction)doTapScreen:(id)sender { //When user touches the screen, either play the sound or go to the next window if (self.player.playing) { [self.player stop]; [thirdWindow makeKeyAndVisible]; } else { NSString *soundFilePath = [[NSBundle mainBundle] pathForResource: @"Tone2" ofType: @"mp3"]; NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: soundFilePath]; AVAudioPlayer *newPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL: fileURL error: nil]; [fileURL release]; self.player = newPlayer; [newPlayer release]; [player prepareToPlay]; [self.player play]; } }
-
Evelyn almost 15 yearsOh! Yeah, I totally meant to say audioPlayerDidFinishPlaying, not applicationDidFinishLaunching. Sorry. I set the delegate to self, and it worked for the first sound. But the problem is not that audioPlayerDidFinishPlaying doesn't work, the problem is that I don't know how to do it again for a second sound. I have two different sounds.
-
Evelyn almost 15 yearsBy the way, when I put in [player setDelegate: self], I get the warning: "class 'ViewController' does not implement the 'AVAudioPlayerDelegate' protocol." Is that a problem?
-
Nico almost 15 yearsYou need to set yourself as both sounds' delegate. The sound will identify itself when it sends you a delegate message, so you can compare it to the sounds you have on hand.
-
Nico almost 15 yearsAs for the warning: It shouldn't break anything, but fix every warning anyway, so that you don't end up with 20 warnings you've been ignoring hiding something really important. You'll need to declare your class as conforming to that protocol.
-
Evelyn almost 15 yearsOh okay! That does work. Thanks. :) I wish I could do a different action for different sounds, though. I can only do the same action for both sounds using that method. (I just have one more question: is there any way for me to use NSTimeInterval to get the duration of a sound? Because that value would be very useful to me in other functions.)
-
Nico almost 15 years“is there any way for me to use NSTimeInterval to get the duration of a sound?” NSTimeInterval is just a primitive type of number. It can't do anything. You can, however, ask the AVAudioPlayer for its duration. See the documentation: developer.apple.com/iphone/library/documentation/AVFoundation/…
-
Nico almost 15 years“I wish I could do a different action for different sounds, though.” You can act conditionally in the delegate method. Ask the player about itself and react to its response, or have two instance variables holding two players, and use the
==
operator to determine which one is talking to you. -
Evelyn almost 15 yearsCool! Thanks. Could you give me any sample code for duration in AVAudioPlayer? That document only gives me the property declaration. Say for example I want a window to appear after the sound has been playing for 15 seconds. How do I do that in code?
-
Nico almost 15 yearsIt's a property, so you access it like any other property. If you don't know how to do that, consult the Objective-C 2.0 Programming Language: developer.apple.com/iphone/library/documentation/Cocoa/…
-
Nico almost 15 yearsAs for making something happen after that many seconds: I'd use NSTimer. (Just remember to invalidate the timer if you pause the player, and re-create it when you resume it.)