I'm beginning iPhone programming and I am trying to make a little test app which plays a sound when you press a button. This question is pretty noob so bear with me. Pretty much I'm trying to figure out how to handle the memory situation. Where do I release the instances created so as to avoid memory issues? Right now if I click on the button multiple times quickly the app crashes. I tried declaring everything in viewDidLoad and putting the release in the dealloc method, but under this design I have to wait until the entire sound is done playing before being able to play the sound again. I want to be able to press the button in the middle of a sound being played and "interrupt it" if that makes sense.
The way its written now is when you press a button, this method is called and the sound is played
-(IBAction)buttonPressed:(id)sender{
NSString *path = [[NSBundle mainBundle] pathForResource:#"filename" ofType:#"mp3"];
AVAudioPlayer* theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error: NULL];
theAudio.delegate = self;
[theAudio play];
}
In this set up it works so that I can "interrupt" an already playing sound by pressing the button again and the sound restarts. However pressing it quickly makes the app crash.
You should release immediately before you exit the method like so:
-(IBAction)buttonPressed:(id)sender{
NSString *path = [[NSBundle mainBundle] pathForResource:#"filename" ofType:#"mp3"];
AVAudioPlayer* theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error: NULL];
theAudio.delegate = self;
[theAudio play];
[theAudio release];
}
or something like that.
Because when you alloc/init a local variable you assign it a retain count of +1. But when you exit the method the reference to that var is still living and you can't access it, which leads in memory leaking. Try to begin from: Memory Management. Good luck.
Related
I'm attempting to use the below code to play an mp3 file. It seems to run fine but no sound comes from the phone. The volume is up, the file is found (if I change the requested file to a name that doesn't exist I get an error), and no errors show up (even in the "playerError"). The only thing I see that might be a problem is perhaps the player deallocating before it finishes playing, but I'm not sure off hand how to fix that. Any suggestions as to what the problem might be and how to fix it? Thank you much!
...
if([responseString isEqual: #"Stop"]){
[self playStop];
}
...
- (void) playStop{
NSString *soundFilePath =
[[NSBundle mainBundle] pathForResource: #"stop"
ofType: #"mp3"];
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];
NSError *playerError;
AVAudioPlayer *newPlayer =
[[AVAudioPlayer alloc] initWithContentsOfURL: fileURL
error: &playerError];
[newPlayer play];
}
If you make your "AVAudioPlayer" an instance variable or a property (instead of a local variable within the function), so that it sticks around instead of being immediately released by ARC when "playStop" finishes, you will likely have much better luck.
What Is the Easiest way to Play Sound on the Iphone? I have an mp3 file, I'd rather keep it and not convert it to other format.
The simplest way I know of to play an MP3 file is to use the AVAudioPlayer class. Basically, just do (skipping error checking, setting delegate for detecting completion, etc):
NSURL* soundUrl = [[NSBundle mainBundle] URLForResource:#"soundFile" withExtension:#"mp3"];
AVAudioPlayer* player = [[AVAudioPlayer alloc] initWithContentsOfURL:soundUrl error:&err];
[player play];
First add AVFoundation Framework to the project [Goto Target> Right click on project>Build Phases>Link Binary with Library> Click on +> select AVFoundation> Add]
// get file path
NSString *soundPath = [[NSBundle mainBundle] pathForResource: fileNameToPlay ofType:#"mp3"];
// allocate and refer to file
AVAudioPlayer *player =[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath: soundPath] error: NULL];
// set delegate
player. delegate = self;
// play
[player play];
Apparently this turned out to be quite a mess, but I found a solution. I'm running XCode 4.4.1.
Here are the steps that worked for me:
Drag mp3 file from finder into XCode project -> Supporting Files. Make sure to copy the file. let's assume the file name is sound.mp3.
Add AVFoundation framework to your project.
import < AVFoundation/AVFoundation.h>
#property (strong) AVAudioPlayer* soundPlayer;
use the following code to init the player and play the mp3:
NSURL *chemin = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/sound.mp3", [[NSBundle mainBundle] resourcePath]]];
NSError *error;
self.soundPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:chemin error:&error];
[self.soundPlayer play];
Now at this point, I got an exception which is described here: AVFoundation iOS 5
In short it means that there is probably a bug in the simulator which shouldn't happen on the device. In my case I turned all exception on, which stopped my code from executing. What you should do is to remove the option of throwing all exceptions.
In addition, in my case it's 3-5 seconds until it first play the sound, so be patient when you don't get the sound right away. After it play for the first time, it will play instantly.
I am trying to create buttons that play single sound files and one button that stops all of the sounds that are currently playing. If the user clicks multiple buttons or the same button in a short amount of time, the app should be playing all of the sounds simultaneously. I have accomplished this without much difficulty using the System Sound Services of iOS. However, the System Sound Services play the sounds through the volume that the iPhone's ringer is set to. I am now trying to use the AVAudioPlayer so that users can play the sounds through the media volume. Here is the code that I am currently (yet unsuccessfully) using the play the sounds:
-(IBAction)playSound:(id)sender
{
AVAudioPlayer *audioPlayer;
NSString *soundFile = [[NSBundle mainBundle] pathForResource:#"Hello" ofType:#"wav"];
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:soundFile] error:nil];
[audioPlayer prepareToPlay];
[audioPlayer play];
}
Whenever I run this code in the iPhone Simulator, it does not play the sound but does display a ton of output. When I run this on my iPhone, the sound simply does not play. After doing some research and testing, I found that the audioPlayer variable is being released by Automatic Reference Counting. Also, this code works when the audioPlayer variable is defined as an instance variable and a property in my interface file, but it does not allow me to play multiple sounds at once.
First thing's first: How can I play an infinite number of sounds at once using the AVAudioPlayer and sticking with Automatic Reference Counting? Also: When these sounds are playing, how can I implement a second IBAction method to stop playing all of them?
First off, put the declaration and alloc/init of audioplayer on the same line. Also, you can only play one sound per AVAudioPlayer BUT you can make as many as you want simultaneously. And then to stop all of the sounds, maybe use a NSMutableArray, add all of the players to it, and then iterate though and [audioplayer stop];
//Add this to the top of your file
NSMutableArray *soundsArray;
//Add this to viewDidLoad
soundsArray = [NSMutableArray new]
//Add this to your stop method
for (AVAudioPlayer *a in soundsArray) [a stop];
//Modified playSound method
-(IBAction)playSound:(id)sender {
NSString *soundFile = [[NSBundle mainBundle] pathForResource:#"Hello" ofType:#"wav"];
AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:soundFile] error:nil];
[soundsArray addObject:audioPlayer];
[audioPlayer prepareToPlay];
[audioPlayer play];
}
That should do what you need.
For whatever reason, I'm having trouble loading up a sound with the AVAudioPlayer. I am testing it on my iPad device.
My code is fairly straight forward, nothing fancy. The framework is imported, delegate implemented. In my viewDidLoad method:
NSString *path = [[NSBundle mainBundle] pathForResource:#"sound" ofType:#"mp3"];
AVAudioPlayer *theAudio = [[AVAudioPlayer alloc]
initWithContentsOfURL:[NSURL fileURLWithPath:path]
error:NULL];
[theAudio setDelegate:self];
[theAudio prepareToPlay];
[theAudio play];
This fails to play the audio. However, by coincidence, when I show a UIAlertView immediately after, I can hear the first 2 seconds of the audio clip play. That is, my app loads, I hear two seconds of audio, then the alert pops up and cuts off the audio.
So it would appear the AVAudioPlayer code somewhat seems to work.
Any idea on whats going on and how I can simply get the audio to play?
The problem is that you are using ARC, and therefore that the AVAudioPlayer is deallocated when the variable goes out of scope. You have to declare the theAudio variable as an instance variable, and assign it in the viewDidLoad. So, in your .h file:
#interface MyViewController : UIViewController {
AVAudioPlayer *theAudio;
...
}
...
#end
Then, get rid of the AVAudioPlayer * from the line where you assign theAudio in viewDidLoad. This will cause your view controller to retain the audio player, and thus will prevent the player from being deallocated before playback.
I developing simple game application in which i playing sound with UIView animation.
theAudioPlayer = [[AVAudioPlayer alloc] init];
[theAudioPlayer initWithContentsOfURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"pageTurn"] ofType:#"mp3"]] error:NULL];
[theAudioPlayer play];
where theAudioPlayer is the instance object of AVAudioPlayer class.
Now my problem is when i playing the game after 10-15 minutes during the animation of UIViews sound going to mute.It never play again, why?
Thanks for sending an viewing my question.
First, the loading code is needlessly complex. You should only initialize the player once and get the sample URL right from the bundle:
theAudioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:
[[NSBundle mainBundle] URLForResource:#"pageTurn" ofType:#"mp3"] error:NULL];
I would not be surprised if that solved the problem alone (given the multiple initialization). And if it does not, which is quite probable, how do you release the player? Do you release it at all?