8

I've searched and I believe my problem is quite unique. I'm aware of the Simulator 5.1 bug when using AVAudioPlayer which isn't my problem. I'm running on a iOS 5.1 device.

Here's my header file:

#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <AVFoundation/AVAudioPlayer.h>

-(IBAction)pushBell;

@end

and my implementation file:

#import "BellViewController.h"

@interface BellViewController ()

@end

@implementation BellViewController

-(IBAction)pushBell {

    NSString *soundPath =[[NSBundle mainBundle] pathForResource:@"bell1" ofType:@"caf"];
    NSURL *soundURL = [NSURL fileURLWithPath:soundPath];
    NSError *error;

    AVAudioPlayer *theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:soundURL error:&error];
    [theAudio setDelegate:self];
    [theAudio setNumberOfLoops:0];
    [theAudio play];

}

@end

And I have a button in my .xib that plays the file.

To make sure I referenced my audio file correctly, I deliberately type a wrong file name and indeed I got an exception. To make sure the file is playable, I mailed it to myself and played it on the device.

When I tap the button I hear nothing. There are no errors. I don't know what is wrong.

More information iPhone 4 with iOS 5.1 Xcode 4.3.2 Audio is about 700kbps converted to .caf format using afconvert from a big .wav file.

Aen Tan
  • 3,305
  • 6
  • 32
  • 52

6 Answers6

20

SOLVED.

1.- Check if your file has been added to "Copy Bundle Resources" in Build Phases. Copy Bundle Resources

2.- ViewController.m

#import <AVFoundation/AVAudioPlayer.h>

@interface ViewController ()
@property (nonatomic, strong) AVAudioPlayer *theAudio;
- (IBAction)pushBell;
@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSString *soundPath =[[NSBundle mainBundle] pathForResource:@"beep-beep" ofType:@"caf"];
    NSURL *soundURL = [NSURL fileURLWithPath:soundPath];

    NSError *error = nil;
    self.theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:soundURL error:&error];
}

- (IBAction)pushBell {
    [self.theAudio play];
}

3.- Connect the IBAction to your button in Interface Builder.

Done.

3lvis
  • 4,190
  • 1
  • 30
  • 35
  • 1
    Funny thing is that, as WAV files, these will play regardless of whether they show up in the Bundle Resources or not. As CAF files, they don't play unless added. – jowie Sep 27 '12 at 09:57
  • 1
    I've also noticed that when you add a WAV file to your Xcode (4.4) project, it will have Add To Target automatically checked. With CAF files, this check box defaults to off. I have no idea why they did this and it catches me out all the time! Anyone else? – jowie Sep 27 '12 at 10:07
  • 1
    Thanks, you saved me so much hassle. This is year 2016 - still not fixed! – Yimin Rong Apr 07 '16 at 10:44
19

This was my issue, so I'm just posting it here in case it helps anyone!

Believe it or not, there appears to be a bug (in iOS 5.1 on iPad 2 at least) where if you had the Side Switch set to Mute and it was Muted, then set the Side Switch to Lock Rotation, AVAudioPlayer sounds WON'T PLAY except through headphones!

So I had to go to the Settings app, change the switch back to Mute, then unmute the iPad, switch it back to Lock Rotation and my app started to work properly.

jowie
  • 8,028
  • 8
  • 55
  • 94
  • tnx jowie,i fixed my issue after wasting lot of time debugging to make sure i am the path correctly to the avplayer object.Nice to learn OS has bugs. – Dinakar May 17 '12 at 13:20
  • yep... iOS is great, but far from perfect ;) – jowie May 17 '12 at 15:51
  • Thanks!!! Saved me at least another few hours of trying to figure this out on iOS 5 and iPad 1 at 1AM – Yan Oct 08 '12 at 02:50
  • I'm not sure if I missed it at the time, but if your side switch is set to Lock Rotation, then Mute is available in the Control Center, and vice versa. It's possible that was the case on iOS 5.1 as well, but I didn't realise it at the time. – jowie Mar 18 '14 at 10:01
  • My god, this got me too. On an iPhone 6. When sound played through other apps (a video I recoded then immediately played back). – escapecharacter Jul 21 '15 at 05:45
16

Your theAudio AVAudioPlayer is deallocated before it can even start playing (since it's allocated as a local variable inside pushBell method.

Change your code to:

header file:

#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <AVFoundation/AVAudioPlayer.h>

@interface BellViewController:UIViewController

@property (nonatomic, strong) AVAudioPlayer *theAudio;

-(IBAction)pushBell;

@end

implementation file:

#import "BellViewController.h"

@implementation BellViewController

@synthesize theAudio = _theAudio;

- (void)viewDidLoad {

    if (!theAudio) {

        NSString *soundPath =[[NSBundle mainBundle] pathForResource:@"bell1" ofType:@"caf"];
        NSURL *soundURL = [NSURL fileURLWithPath:soundPath];
        NSError *error;

        _theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:soundURL error:&error];
        [self.theAudio setDelegate:self];
        [self.theAudio setNumberOfLoops:0];

        [self.theAudio prepareToPlay];
    }
}

-(IBAction)pushBell {

   [self.theAudio play];
}

@end

I'm assuming that BellController is a UIViewController, if it's a different kind of class just modify the code accordingly.

Rok Jarc
  • 18,765
  • 9
  • 69
  • 124
  • 2
    "Audio not playing" seems to reappear so many times in my coding life, it's just a different reason every time! And this one was my latest... With ARC switched on, `alloc init` isn't enough to ensure an object stays in memory! Thanks :) – jowie Jun 14 '12 at 15:39
4

I think that it is a memory issue, you should instantiate the AVAudioPlayer *theAudio as a global class object and initialise it in the init method. Then just run the [theAudio play]; method in the -(IBAction)pushBell method.

I responded do a similar issue related to playing a system sound (which in fact is what you are trying to do), check it out my response is at the bottom:

Couldn't play system sound after switching to iOS 5

By the way consider playing the bell as a system sound, AVAudioPlayer is more appropriate to play sound tracks, not bells and effects.

I hope that it helps.

Community
  • 1
  • 1
2

I agree with hooleyhoop. Try

NSLog(@"%@", error.userInfo) 

to see what's coming out.

Another alternative would be to set up the player object in either viewDidLoad or initWithNib and storing it as a property on your object. This way you can use something like [self.theAudio prepareToPlay];

To avoid loading up the audio each time you press the button, which could save you some time if it's high quality audio. Then just call [self.theAudio play]; in you IBAction method.

Sorry, if this answer is a little sloppy - typing on an iPad so can't double check properly.

Unheilig
  • 16,196
  • 193
  • 68
  • 98
Jon Hocking
  • 229
  • 3
  • 11
1

You should give it some time to prepare the pronunciation since it's probably buffering from a URL.

The code:

[theAudio prepareToPlay];

[self performSelector:@selector(playMusic) withObject:nil afterDelay:3.0];
Sidwyn Koh
  • 1,742
  • 2
  • 21
  • 29