iPhone App - WAV sound files don't play - iphone

I searched on here and tried out all the different solutions given, but nothing worked. So let me ask:
I'm trying to play a sound on an iPhone app when a button is pressed. I imported the Audio framework, hooked up the button with the method, have the WAV sound file in the bundle, and use the following code to play the sound:
NSString *path = [NSString stringWithFormat:#"%#%#", [[NSBundle mainBundle] resourcePath], #"/filename.wav"];
SystemSoundID soundID;
NSURL *filePath = [NSURL fileURLWithPath:path isDirectory:NO];
AudioServicesCreateSystemSoundID((CFURLRef)filePath, &soundID);
AudioServicesPlaySystemSound(soundID);
But it doesn't play sound when I press a button. (Yes, my sound is on.)
Any ideas why this might be, and how I can fix it? I'd be happy to provide any more information if it helps.

First of all, the preferred sound format for iPhone is LE formatted CAF, or mp3 for music. You can convert a wav to caf with the built in terminal utility:
afconvert -f caff -d LEI16 crash.wav crash.caf
Then the easiest away to play a sound is to use the AVAudioPlayer... this quick function can help you load a sound resource:
- (AVAudioPlayer *) soundNamed:(NSString *)name {
NSString * path;
AVAudioPlayer * snd;
NSError * err;
path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:name];
if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
NSURL * url = [NSURL fileURLWithPath:path];
snd = [[[AVAudioPlayer alloc] initWithContentsOfURL:url
error:&err] autorelease];
if (! snd) {
NSLog(#"Sound named '%#' had error %#", name, [err localizedDescription]);
} else {
[snd prepareToPlay];
}
} else {
NSLog(#"Sound file '%#' doesn't exist at '%#'", name, path);
}
return snd;
}

I don't know if you have solved the problem, but for me, on iOS 7, sometimes the (__bridge CFURLRef) casting won't work, in which case, if you print out the result of (__bridge CFURLRef)[NSURL fileURLWithPath:path], it will be 0x0. This leads to failure of AudioServicesCreateSystemSoundID(). The return value of the function is type of OSStatus. If it fails, the function will return -50, which means one or more parameters are invalid. (If it executes successfully, it returns 0.)
I solved this by using the C style function getting the path of the file:
CFBundleRef mainBundle = CFBundleGetMainBundle ();
CFURLRef soundFileUrl;
soundFileUrl = CFBundleCopyResourceURL(mainBundle, CFSTR("fileName"), CFSTR("wav"), NULL);
AudioServicesCreateSystemSoundID(soundFileUrl, &soundID);

Related

iOS xcode 4.6 Adding Audio to App

I'm trying to play an audio file in the background of my app and it isn't playing. The code that I have is:
SystemSoundID SoundID;
NSString *soundFile = [[NSBundle mainBundle] pathForResource:#"HoHey" ofType:#"mp3"];
AudioServicesCreateSystemSoundID((__bridge CFURLRef)[NSURL fileURLWithPath:soundFile], &SoundID);
AudioServicesPlaySystemSound(SoundID);
NSLog(#"%# is playing\n", soundFile);
The NSLog displays "HoHey.mp3 is playing" but I can't hear it playing. My volume is turned up btw because I hear my videos play when I play them. Any ideas?
You likely have an error somewhere along the way. Try code that looks like this:
SystemSoundID soundID;
NSString *soundFile = [[NSBundle mainBundle] pathForResource:#"HoHey" ofType:#"mp3"];
if(soundFile)
{
OSStatus status = AudioServicesCreateSystemSoundID((__bridge CFURLRef)[NSURL fileURLWithPath:soundFile], &soundID);
if(status == noErr)
{
AudioServicesPlaySystemSound(soundID);
NSLog(#"%# is playing\n", soundFile);
} else {
NSLog( #"no sound id created; error status code is %d", status);
}
} else {
NSLog( #"couldn't find sound file... is it really in your app bundle?");
}
P.S., don't capitalize Objective-C variable names (e.g. "soundID" instead of "SoundID").

Play a .wav with Audio Toolbox

I am trying to play a .wav file using Audio Toolbox. I have this so far:
However my file will not play. The If condition is triggered right, however it doesn't play.
It will print the error message if the file isn't there however. Any clue what is wrong?
-(void) playSound : (NSString *) fName : (NSString *) ext
{
SystemSoundID audioEffect;
NSString *path = [[NSBundle mainBundle] pathForResource : fName ofType :ext];
if ([[NSFileManager defaultManager] fileExistsAtPath : path])
{
NSURL *pathURL = [NSURL fileURLWithPath : path];
AudioServicesCreateSystemSoundID((__bridge CFURLRef) pathURL, &audioEffect);
AudioServicesPlaySystemSound(audioEffect);
}
else
{
NSLog(#"error, file not found: %#", path);
}
AudioServicesDisposeSystemSoundID(audioEffect);;
}
You can't dispose of the sound ID immediately after telling it to play, since this causes the playback to stop. That's why you didn't hear it in the first place.
What you should do instead is hold a reference to the ID in a property on whatever object is responsible for creating it (e.g., a view controller). You'd declare it like this in your interface declaration:
#property(nonatomic, assign) SystemSoundID audioEffect;
...and subsequently assign to it like this:
AudioServicesCreateSystemSoundID((__bridge CFURLRef) pathURL, &_audioEffect);
This will not only allow you to properly dispose of it at a later time when you know you're done with it (e.g. in viewDidUnload), but will also prevent you from having to read the file in from disk each time you want to play it back, since each ID can be played an unlimited number of times.
One final hint: you can ask for the URL to a bundle resource directly instead of requesting a string and then transforming it to a URL.
NSURL *audioURL = [[NSBundle mainBundle] URLForResource:fName withExtension:ext];
if([[NSFileManager defaultManager] fileExistsAtPath:[audioURL path]])
// ...
I figured it out from Warrenm's comment. I had to delete the last line, as it was killing the sound milliseconds after it was set to play, and therefore can't be heard.
-(void) playSound : (NSString *) fName : (NSString *) ext
{
SystemSoundID audioEffect;
NSString *path = [[NSBundle mainBundle] pathForResource : fName ofType :ext];
if ([[NSFileManager defaultManager] fileExistsAtPath : path])
{
NSURL *pathURL = [NSURL fileURLWithPath : path];
AudioServicesCreateSystemSoundID((__bridge CFURLRef) pathURL, &audioEffect);
AudioServicesPlaySystemSound(audioEffect);
}
else
{
NSLog(#"error, file not found: %#", path);
}
}

How to stop playing sound in Xode with AudioToolbox framework? [duplicate]

Pretty simple, I'm using one button that generates a random number and then with a switch/case, it animates an image and plays a sound. My problem is that when you press the button again, the sound that was playing before doesn't stop and the sound overlaps.
Here's the code:
- (IBAction) pushme: (id) sender{
int random = (arc4random()%10);
switch (random) {
case 0: {
[ANIMATION NUMBER 0]
NSString *path = [NSString stringWithFormat:#"%#%#",[[NSBundle mainBundle] resourcePath],#"/sound0.wav"];
SystemSoundID soundID;
NSURL *filePath = [NSURL fileURLWithPath:path isDirectory:NO];
AudioServicesCreateSystemSoundID((CFURLRef)filePath, &soundID);
AudioServicesPlaySystemSound(soundID);
}
break;
case 1: {
[ANIMATION NUMBER 1]
NSString *path = [NSString stringWithFormat:#"%#%#",[[NSBundle mainBundle] resourcePath],#"/sound1.wav"];
SystemSoundID soundID;
NSURL *filePath = [NSURL fileURLWithPath:path isDirectory:NO];
AudioServicesCreateSystemSoundID((CFURLRef)filePath, &soundID);
AudioServicesPlaySystemSound(soundID);
} break; //Lots more cases after this one
I know that this is not the best way to do it, declaring the same variable over and over.
but is there a way to stop it before it plays another one?
I just dicovered the answer to my own question.
What I did was
Declare SoundSystemID soundID; in the header.
Add this line before the random number gets generated: AudioServicesDisposeSystemSoundID(soundID);
Remember that if you are going to play the sound again, you will need to load the resource again after disposing of it.
Thank you guys, anyway.

AVAudioPlayer -> not working

Audio Player works fine if I initiate it for 20 to 30 times but after that it shows the following error
Error Domain=NSOSStatusErrorDomain Code=-43 "The operation couldn’t be completed. (OSStatus error -43.)"
The code currently I am using is as follows
- (void)playShortSound:(NSString *)fileName type:(NSString *)type
{
if (!isSound) {
return;
}
NSString *soundFilePath =[[NSBundle mainBundle] pathForResource: fileName ofType: type];
NSURL *fileURL = [[[NSURL alloc] initFileURLWithPath: soundFilePath] autorelease];
NSError *error;
AVAudioPlayer *newPlayer =[[AVAudioPlayer alloc] initWithContentsOfURL: fileURL
error: &error];
//newPlayer.numberOfLoops = 0;
newPlayer.volume=1.0;
if (newPlayer == nil){
NSLog(#"%#",[error description]);
//[self playShortSound:fileName type:type];
//return;
}
else{
[newPlayer play];
newPlayer.delegate=self;
}
}
- (void) audioPlayerDidFinishPlaying: (AVAudioPlayer *) player
successfully: (BOOL) completed {
if (completed == YES) {
NSLog(#"Sound Playing complete");
}else {
NSLog(#"error in completion of %#",player.url);
}
}
I was having the same problem and instead of init the player from url i did it from NSData.
NSString *soundFilePath =[[NSBundle mainBundle] pathForResource: fileName ofType: type];
NSData *soundData = [[NSData alloc] initWithContentsOfFile:soundFilePath];
NSError *error;
AVAudioPlayer *newPlayer =[[AVAudioPlayer alloc] initWithData: soundData
error: &error];
It seem to solved my problem hope it does yours.
By calling the method many times you are allocating the instance of AVAudioPlayer newPlayer many times. This will certainly cause you problems because of the memory allocated. Just make sure you release the objects that you own once you are done using them.
Did you set AudioSessionCategory?
{NSError *setCategoryError = nil;
BOOL success = [[AVAudioSession sharedInstance] setCategory: avaudiosessioncategoryplayandrecorderror: &setCategoryError];
}
I was trying to play files in my app by picking them from the iPod library when I got this error code. I found that in my iPod library on the device, I had a duplicate entry for the same song. Music player that comes with iOS was able to play one and not the other. That means one entry was not valid anyway. Probably removed from the device but iTunes/iOS did not do proper housekeeping.
It seems that the reference to the non-playable entry existed within the "Recently Added" playlist which is automatically created by the system. I had picked the same file from "Recently Added" playlist to play in the app.
Side Note: I had removed the file from the manually created playlist in which it existed (removed from the iOS device itself).
In short it seems that the file that I loaded into the AVAudioPlayer instance was not available on the device anymore or its referencing URL did not give back a proper file to play. So common reason for this error would be when the player does not get the file to load based on the URL given to it.

playing a sound, waiting it to finish playing and continue (iphone)

i'm new with the iphone and objective c, so far, I have been able to code some small examples.
i would like to play a sound and, continue with rest of the code when the sample finishes playing, i.e:
printf("hello");
playASound["file.wav"];
printf("world");
actually i'm getting: print hello, play the file and print world at the same time
but
what i want is: print hello, play the file, print world...
so, the question is how do i get it?
thanks
btw. here is the playASound code:
-(void) playASound: (NSString *) file {
//Get the filename of the sound file:
NSString *path = [NSString stringWithFormat:#"%#/%#",
[[NSBundle mainBundle] resourcePath],
file];
SystemSoundID soundID;
//Get a URL for the sound file
NSURL *filePath = [NSURL fileURLWithPath:path isDirectory:NO];
AudioServicesCreateSystemSoundID((CFURLRef)filePath, &soundID);
//play the file
AudioServicesPlaySystemSound(soundID);
}
From the documentation:
Discussion This function plays a short
sound (30 seconds or less in
duration). Because sound might play
for several seconds, this function is
executed asynchronously. To know when
a sound has finished playing, call the
AudioServicesAddSystemSoundCompletion
function to register a callback
function.
So you'll need to break up your function into two pieces: a function that calls PlayASound and prints "Hello", and a function that is called by the system when the sound is finished playing and prints "World".
// Change PlayASound to return the SystemSoundID it created
-(SystemSoundID) playASound: (NSString *) file {
//Get the filename of the sound file:
NSString *path = [NSString stringWithFormat:#"%#/%#",
[[NSBundle mainBundle] resourcePath],
file];
SystemSoundID soundID;
//Get a URL for the sound file
NSURL *filePath = [NSURL fileURLWithPath:path isDirectory:NO];
AudioServicesCreateSystemSoundID((CFURLRef)filePath, &soundID);
//play the file
AudioServicesPlaySystemSound(soundID);
return soundID;
}
-(void)startSound
{
printf("Hello");
SystemSoundID id = [self playASound:#"file.wav"];
AudioServicesAddSystemSoundCompletion (
id,
NULL,
NULL,
endSound,
NULL
);
}
void endSound (
SystemSoundID ssID,
void *clientData
)
{
printf("world\n");
}
See also docs for AudioServicesAddSystemSoundCompletion and AudioServicesSystemSoundCompletionProc.