Do an action when a sound has finished playing in AVAudioPlayer?

15,462

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")
    }
Share:
15,462

Related videos on Youtube

Evelyn
Author by

Evelyn

Java, python, and chocolate.

Updated on September 12, 2020

Comments

  • Evelyn
    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
    Evelyn almost 15 years
    Oh! 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
    Evelyn almost 15 years
    By 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
    Nico almost 15 years
    You 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
    Nico almost 15 years
    As 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
    Evelyn almost 15 years
    Oh 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
    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/AVFoundatio‌​n/…
  • Nico
    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
    Evelyn almost 15 years
    Cool! 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
    Nico almost 15 years
    It'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
    Nico almost 15 years
    As 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.)