12

I have imported audio toolbox and avfoundation to my class and added the frameworks to my project and am using this code to play a sound:

- (void)playSound:(NSString *)name withExtension:(NSString *)extension
{
    NSURL* soundUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:name ofType:extension]]; 
    AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundUrl error:nil];
    audioPlayer.delegate = self;
    audioPlayer.volume = 1.0;
    [audioPlayer play];
}

I call it like this:

[self playSound:@"wrong" withExtension:@"wav"];

However I get zero sound.

halfer
  • 19,824
  • 17
  • 99
  • 186
Josh Kahane
  • 16,765
  • 45
  • 140
  • 253
  • 1
    `soundURL` is valid and `audioPlayer` is non-nil? Might try passing an `NSError` object into the initialization of the `AVAudioPlayer` and see if you are getting an error. – gschandler Jun 01 '12 at 19:42
  • Is you `audioPlayer` non nil after you `init`? If not use the error argument and you might get some useful help... – Paul.s Jun 01 '12 at 19:43
  • I've done `NSError *err;` and added `&err` to the `audioPlayer` and printing it like so: `NSLog(@"%@", err);` and all I get is `(null)`. – Josh Kahane Jun 01 '12 at 19:53
  • Is your `audioPlayer` non nil? – Paul.s Jun 01 '12 at 20:03
  • Does the sounds actually have any sound on it (try playing in finder). Is your mute switch on? – Paul.s Jun 01 '12 at 20:18
  • The file definitely has sound and the iPad is definitely not muted and has the volume turned up. – Josh Kahane Jun 01 '12 at 20:22
  • This is super strange. It works if I declare the AVAudioPlayer in my herder file opposed to right at the moment. Why? – Josh Kahane Jun 01 '12 at 20:46
  • 1
    Are you using ARC? I guess it's possible as no one has a strong reference, ARC could have potentially dealloc'ed it in the time it was taking to load the buffer and play the sample? – Paul.s Jun 01 '12 at 23:32
  • I can confirm that the problem is with ARC. – ABCD Aug 03 '12 at 06:30

4 Answers4

27

Updated answer:

I've got the issue. It's with ARC and has nothing to do with prepareForPlay. Simply make a strong reference to it and it will work.

as stated below by user: Kinderchocolate :)

In code:

.h
~
@property (nonatomic, strong) AVAudioPlayer *player;


.m
~
@implementation
@synthesize _player = player;
Ben Packard
  • 26,102
  • 25
  • 102
  • 183
esreli
  • 4,993
  • 2
  • 26
  • 40
  • 2
    What would this add? The docs state that when calling `play ... this method implicitly calls the prepareToPlay method if the audio player is not already prepared to play.` – Paul.s Jun 01 '12 at 23:33
  • yes , i have got same issue,after disable arc for particular file , and getting sound – KETAN Oct 25 '12 at 07:26
18

Yes, ARC was the problem for me too. I solved just adding:

In .h

@property (strong, nonatomic) AVAudioPlayer *player;

In .m

@synthesize player;

-(void)startMusic{
    NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:@"Riddls" ofType:@"m4a"];
    NSURL *soundFileURL = [NSURL fileURLWithPath:soundFilePath];
    player = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL error:nil];
    player.numberOfLoops = -1; //infinite
    [player play];
}
h3r3b
  • 191
  • 2
  • 4
  • Thanks, this also solved my problem. What got me confused was that the AVAudioPlayer would still play for the duration of the audio clip, even though ARC had released the data. Even strange, on earphones I could hear a silent hissing during that time. – Simo A. Nov 18 '13 at 07:11
  • If you don't want to declare a strong property for the audio player, you can simply create a `static` pointer to it. That will keep it in memory long enough to finish playing the sound, even after its declared scope exits. – Eric Baker Jul 22 '15 at 16:04
9

I've got the issue. It's with ARC and has nothing to do with prepareForPlay. Simply make a strong reference to it and it will work.

ABCD
  • 7,914
  • 9
  • 54
  • 90
  • what exactly do You mean by making a strong reference? – Peter V Sep 01 '12 at 16:30
  • AVAudioPlayer *audioPlayer = ... in the original code. After the end of the function, audioPlayer gets released. You'll need to hold a strong reference to the instance. – ABCD Sep 02 '12 at 14:46
  • This got me too. Certainly an annoying bug/feature/facet of ARC. I was logging that I def had a player object, no error object, the file existed at the URL and logging that the player still existed after the call to `[player play]` and no sound. I guess the actual playing is on another thread and by the time that kicks in, the player obj reference is nil, thx to ARC. – Brynjar Oct 08 '12 at 14:30
1

If you declare your AVAudioPlayer in a class method like -viewDidLoad, and ARC is on, the player will be released right after -viewDidLoad and become nil, (-(BOOL)play method won't block a thread) this will happend in milliseconds, obvious "nil" can't play anything, so you won't even hear a sound.

Better declare the player as ViewController's @property or make it as a global singleton, anything can last longer.

Pride Chung
  • 573
  • 7
  • 20