Playing sound though http server iOS - iphone

Hi I want to play a mp3 file via my server e.g. http://test.com/hi.mp3
At the moment the code plays the file if its in the directory of the code.
The code also enables only 1 sound at a time.
- (IBAction)oneSound:(id)sender; {
NSString *path = [[NSBundle mainBundle] pathForResource:#"1" ofType:#"mp3"];
if (theAudio) [theAudio release];
NSError *error = nil;
theAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error];
if (error)
NSLog(#"%#",[error localizedDescription]);
theAudio.delegate = self;
[theAudio play];
}
However this code here enables me to play the sound through the http server, but I can play multiple sounds at once, I need the sound in sessions so only 1 sound can play at once. I have 10 sounds.
- (IBAction)oneSound:(id)sender; {
AVPlayer *player = [[AVPlayer playerWithURL:[NSURL URLWithString:#"http://www.mysite.com/hi.mp3"]] retain];
[player play];
}

My suggestion would be to move the pointer for your player from being declared in that method so that it is declared at a module level (in the .h file) - either just defined in the interface, or defined as a #property. Then you can access this player in another method later.
Then when you wish to switch to a new sound in another method you could try:
[player pause]; // stop the player from playing
[player release]; // free the reference count
// start a new plaer
player = [[AVPlayer playerWithURL:
[NSURL URLWithString:#"http://www.mysite.com/nextsound.mp3"]] retain];
You should be careful with the 'retain' call here. The playerWithURL will be passing back an autoreleased object, so depending on what you are doing elsewhere with autorelease pools, and depending on whether you are using a property including (retain) in its definition, you may not need to call retain here.

Related

Reliable Way to Add Sound to UIButton

I am trying to add a tap-sound to a UIButton to play when it is pushed. So far, I've tried two methods, but none worked out quite as well as I hoped.
I have tried using simple SystemSounds, but they are an ugly solution, as the user have no (or rather very limited) control over the audio volume.
I also tried AVAudioPlayer in the following form (called in the ViewController's init method):
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient
error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];
[[AVAudioSession sharedInstance] setDelegate:self];
NSString *filePath = [[NSBundle mainBundle]
pathForResource: #"button_pushed"
ofType: #"wav"];
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: filePath];
self.buttonPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL: fileURL
error: nil];
[buttonPlayer prepareToPlay];
[buttonPlayer setDelegate: self];
This second method seemed to work a lot better than the first one; especially when I called sound with the following statement:
if (self.clickPlayer.playing) {
[self.clickPlayer stop];
self.clickPlayer.currentTime = 0;
[self.clickPlayer play];
}
else {
[self.clickPlayer play];
}
The above ensured that I got a very fast response when I pushed the button repeatedly. Fast response time, by the way, is essential in my app, and unfortunately, this is where this second methods fails.
If I let the application idle for about 10 seconds, loading the first sound takes a noticeable delay (then, it becomes fast and responsive again). Not only that, it also delays the button from being pushed with it. While this delay is very tiny (probably the fraction of a second), unfortunately it does effect the usability of my application. It is as if the sound was becoming deallocated automatically and needed to be initialized or put into the memory every time I did not use it for a while.
Is there a workaround to always keep the sound available and avoid the delay or another, possibly simple, method to implement button sounds?
A few more info:
1. I use ARC
2. I do not use IB
3. Currently, there are no audio delegate methods implemented
4. The ability to play audio in the background from other applications is kind of important
5. The delay occurred on an iPhone 5; so, I can only imagine how long it would take on less powerful devices...
I managed to solve this problem by creating a "blank" player that continuously fires off a tiny .wav file with no sound, therefore keeping the AVPlayer alive. This is probably not the most elegant solution, but it does work, while it does not seem to affect the performance of the program. Here's what you need to do:
Create a silent .wav file of 0.1 seconds long (the smaller the better).
Initialize a player for it:
NSString *filePath = [[NSBundle mainBundle] pathForResource: #"silence"
ofType: #"wav"];
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: filePath];
silencePlayer = [[AVAudioPlayer alloc] initWithContentsOfURL: fileURL
error: nil];
[silencePlayer prepareToPlay];
[silencePlayer setDelegate: self];
Then make it fire every second or so:
timer = [NSTimer scheduledTimerWithTimeInterval:1.0f
target:self
selector:#selector(repeatSilence)
userInfo:nil
repeats:YES];
Finally, create the called method (- (void) repeatSilence { } ) to play the sound:
if (self.silencePlayer.playing) {
[self.silencePlayer stop];
self.silencePlayer.currentTime = 0;
[self.silencePlayer play];
}
else {
[self.silencePlayer play];
}
Not entirely sure, but wouldn't it go faster if you make an NSData of the path and change [[AVAudioPlayer alloc] initWithContentsOfURL to [[AVAudioPlayer alloc] initWithData?

I need to create an audio player with 4-5 melodies

I am new in Iphone SDK programming
I need to create audio player but without array. Melodies have names "sound1, sound2, sound3..."
My code here:
NSUInteger x;
for (x=1; x<=tuneNums; x++)
{
path = [[NSBundle mainBundle] pathForResource:#"sound%d" ofType:#"wav"];
if([[NSFileManager defaultManager] fileExistsAtPath:path])
{
aSound = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error];
[aSound setNumberOfLoops:0];
aSound.delegate = self;
[aSound prepareToPlay];
}
}
All button I have and work great, but only with one mellody:( But how release 4-5 melodies i dont know :(
P.S. Forgive me for my english I'm just out of Siberia
You are allocating an AVAudioPlayer on each cycle, and you get only one 'melody' because that's the one allocated in the last cycle.
As 7KV7 pointed out, you should allocate one AVAudioPlayer when the user presses a button, play the corresponding audio file, and then release/recreate it when another button is pressed.
Something like:
- (void)button1Pressed:(id)sender {
// release the current player
if(aSound) {
[aSound release], aSound = nil;
}
// create a new player with the first file
aSound = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error];
[aSound setNumberOfLoops:0];
aSound.delegate = self;
[aSound prepareToPlay];
}
How to determine which audio file to play when a button is pressed is up to you. If you are going to have only four audio files, the simplest way is to have a fixed number of buttonPressed selectors (e.g. button1Pressed, button2Pressed) and associate them to your four buttons.
if i got you right you should add the method-
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{
[player release];
}
and don't forget to set your view controller as the player delegate.
aSound.delegate=self;

iPhone, AVAudioPlayer and multiplesounds

im new developer and making my firt iPhone app ,and i want to make button to on/off multiplesounds , example when i press button for multiple sounds after when i play sounds it plays all sound at same time and if its off can play only one sounds, what code is to make ON/OFF multiple sounds play?
sorry for my bad english, Tanks!
Sania,
In order to play multiple sounds at once, Apple recommends using the .caf format which is hardware decoded. Also, you basically just create a new AVAudioPlayer object for each sound file instead of re-using the same object in the case where you only want one sound to play at a time.
I won't go into much of the code since there is already a LOT out there if you just search for it... but here are some helpful links to get you started:
http://developer.apple.com/iphone/library/documentation/AVFoundation/Reference/AVAudioPlayerClassReference/Reference/Reference.html
http://www.mobileorchard.com/easy-audio-playback-with-avaudioplayer/
// a function I use to play multiple sounds at once
- (void)playOnce:(NSString *)aSound {
// Gets the file system path to the sound to play.
NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:aSound ofType:#"caf"];
// Converts the sound's file path to an NSURL object
NSURL *soundURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];
self.soundFileURL = soundURL;
[soundURL release];
AVAudioPlayer * newAudio=[[AVAudioPlayer alloc] initWithContentsOfURL: soundFileURL error:nil];
self.theAudio = newAudio; // automatically retain audio and dealloc old file if new file is loaded
[newAudio release]; // release the audio safely
// buffers data and primes to play
[theAudio prepareToPlay];
// set it up and play
[theAudio setNumberOfLoops:0];
[theAudio setVolume: volumeLevel];
[theAudio setDelegate: self];
[theAudio play];
}

Delay in playing sounds using AVAudioPlayer

-(IBAction)playSound{ AVAudioPlayer *myExampleSound;
NSString *myExamplePath = [[NSBundle mainBundle] pathForResource:#"myaudiofile" ofType:#"caf"];
myExampleSound =[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:myExamplePath] error:NULL];
myExampleSound.delegate = self;
[myExampleSound play];
}
I want to play a beep sound when a button is clicked. I had used the above code. But it is taking some delay in playing the sound.
Anyone please help.
There are two sources of the delay. The first one is bigger and can be eliminated using the prepareToPlay method of AVAudioPlayer. This means you have to declare myExampleSound as a class variable and initialize it some time before you are going to need it (and of course call the prepareToPlay after initialization):
- (void) viewDidLoadOrSomethingLikeThat
{
NSString *myExamplePath = [[NSBundle mainBundle]
pathForResource:#"myaudiofile" ofType:#"caf"];
myExampleSound =[[AVAudioPlayer alloc] initWithContentsOfURL:
[NSURL fileURLWithPath:myExamplePath] error:NULL];
myExampleSound.delegate = self;
[myExampleSound prepareToPlay];
}
- (IBAction) playSound {
[myExampleSound play];
}
This should take the lag down to about 20 milliseconds, which is probably fine for your needs. If not, you’ll have to abandon AVAudioPlayer and switch to some other way of playing the sounds (like the Finch sound engine).
See also my own question about lags in AVAudioPlayer.
AudioServicesPlaySystemSound is an option. Tutorial here, sample code here.

Is this the right way to use AVAudioPlayer, does my code look right?

Considering the code:
soundFilePath = [[NSBundle mainBundle] pathForResource: #"Sound" ofType: #"wav"];
fileURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];
avPlayerNextLevel = [[AVAudioPlayer alloc] initWithContentsOfURL: fileURL error: nil];
avPlayerNextLevel1.volume = volume ;
[soundFilePath release];
[fileURL release];
To play the sound I then do
if([avPlayerNextLevel prepareToPlay]){
[avPlayerNextLevel play];
}
I do this many times within my game. Sometimes on the simulator , the sound stops playing. And when sometimes I detect memory leaks with AvAudioPlayer.
Does everything look alright with my code ?
You'll need to release the instance of AVAudioPlayer that you created. Since the above code sets the delegate to self, just implement the following method and release there:
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
NSLog(#"Audio finished playing.");
[player release];
}
Why are you releaseing a non-owning reference (soundFilePath)?
You don't need to manually prepareToPlay if you're going to invoke play right after.
Quoting the documentation for play:
Discussion
Calling this method implicitly calls the prepareToPlay method if the audio player is not already prepared to play.
Personally, I do this:
NSURL *soundUrl = [NSURL fileURLWithPath:
[[NSBundle mainBundle] pathForResource:track
ofType:nil]];
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundUrl
error:nil];
[audioPlayer setDelegate:self];
[audioPlayer play];
Where audioPlayer is an ivar and track is an lvar of type NSString* which I obtained earlier from wherever I configure the next song to play.
I've been working on something similar but I was using a slightly different piece of code. Unfortunately, I got memory leaks, therefore I decided to give a try to the code you posted. Same result: memory leaks again when I invoke [audioPlayer play];
I can't really figure out what's going on. Are you guys aware of any memory leaks when AVAudioPlayer is involved?