AVaudioPlayer regarding song overlapping - iphone

I have using AVAudioPlayer in my app but the problem is that when i play the song from list it will played while before stopping the song i am again goes to song list then select another song then both song will start playing simultaneously so please tell me the code which will terminate my first song.
I use flag variable for initializing the song file---
fileURL = [[NSURL alloc] initFileURLWithPath: [[NSBundle mainBundle] pathForResource:#" Om Namo" ofType:#"aac"]];
self._player = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];
if (self._player)
{
_fileName.text = [NSString stringWithFormat: #"%# (%d ch.)", [[self._player.url relativePath] lastPathComponent], self._player.numberOfChannels, nil];
[self updateViewForPlayerInfo];
[self updateViewForPlayerState];
}
[fileURL release];
break;
Play and push function---
- (void)startPlayback
{
if ([self._player play])
{
//[self stop];
[self updateViewForPlayerState];
self._player.delegate = self;
}
else
NSLog(#"Could not play %#\n", self._player.url);
}
- (void)pausePlayback
{
[self._player pause];
[self updateViewForPlayerState];
}
I also make stop function---
-(void)stop
{
[_player release];
self._player=nil;
}
Please help me .
Is correct my stop function.
and where i put our stop function or any other solution to fix this problem...

I can think of 3 things :
1) You can make code look like code by putting 4 spaces infront of each line. The reason you've gt no answers so far is probably because your question is almost unreadable ;)
2) In your stop method you might want to try this :
- (void) stop {
[_player stop];
self._player = nil;
}
3) Apple highly discourage using an underscore in front of member names. I've never run into problems but I'd rename _player to player.

Related

Buffering label in a stream using MPMoviePlayer

Im making a radio streaming application, my app is working perfectly. I have two buttons in my screen one for playing and the other for pausing, also I have a label that indicates the state of my player. I have no problem making this label show the state "Playing" or "Paused" my problem is that when I press the play button there is a time where the buffer is gathering information and I can't figure out a way to show a "Buffering..." label before the player start to stream the audio.
This is the code Im using for streaming the radio station.
NSString *url = [NSString stringWithFormat:#"http://66.7.218:8816"];
player = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL URLWithString:url]];
player.movieSourceType = MPMovieSourceTypeStreaming;
player.view.hidden = YES;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance]setActive:YES error:nil];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[player prepareToPlay];
[player play];
Im usin a function I created called changeStatus and this function is called each second to identify the status of the player.
-(void)changeStatus
{
if (player.loadState == MPMovieLoadStateUnknown) {
status.text = #"Buffering...";
}
if(player.playbackState == MPMoviePlaybackStatePlaying)
{
status.text = #"Playing.";
}
if(player.playbackState == MPMoviePlaybackStatePaused)
{
status.text = #"Paused";
}
}
I really need to solve this problem and Ive tried all I can to solve it. Hope you can help me! Thanks in advance.
I achieved to solve the problem. The part that was missing is the if clause which gives the signal to start playing only when the player is prepared to play. Without that the player starts to play before the buffer is completely loaded so it plays no audio. And that was the reason my Playing label showed immediately instead of the buffering one.
NSString *url = [NSString stringWithFormat:#"http://66.7.218:8816"];
player = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL URLWithString:url]];
player.movieSourceType = MPMovieSourceTypeStreaming;
player.view.hidden = YES;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance]setActive:YES error:nil];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[player prepareToPlay];
if(player.isPreparedToPlay)
{
[player play];
}
Adittionally, the MPMoviePlaybackStateInterrupted refers to the buffering process while doing an stream. So if you want to make something happens in the buffering process refer to this method.
-(void)changeStatus
{
if(player.playbackState == MPMoviePlaybackStatePlaying)
{
status.text = #"Playing.";
}
if(player.playbackState == MPMoviePlaybackStateInterrupted)
{
status.text = #"Buffering...";
}
}
Thanks a lot to the user That Guy who helped me solving this.
Actually there's a notification called
MPMediaPlaybackIsPreparedToPlayDidChangeNotification
The observer will get notified after it is ready to play. It is more or less the same effect but with different mechanism.

How to play more than two songs using AVAudioPlayer

I want to play more than two song in my app. how do I can do it using AVAudioPlayer ?
I was going to type up the answer, but google provides a perfectly good answer:
http://www.iphonedevsdk.com/forum/iphone-sdk-development/27285-play-sequence-audio-files-avaudioplayer.html
The first piece of code from the page will just call all the sounds in sequence:
- (void)playSoundSequence {
// Make array containing audio file names
NSArray *theSoundArray = [NSArray arrayWithObjects:#"one",#"two",nil];
int totalSoundsInQueue = [theSoundArray count];
for (int i=0; i < totalSoundsInQueue; i) {
NSString *sound = [theSoundArray objectAtIndex:i];
// Wait until the audio player is not playing anything
while(![audioPlayer isPlaying]){
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:sound ofType:#"wav"]] error:NULL];
self.audioPlayer = player;
[player release];
[audioPlayer setVolume:1.0f];
[audioPlayer play];
//Increment for loop counter & move onto next iteration
i++;
}
}
}
But, you are probably better off using an AVAudioPlayerDelegate:
If you don't want to wait in the loop, you can also make your
controller an AVAudioPlayerDelegate and implement
Code:
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
This will be called when the end of the audio file is reached, at
which point you would start playing the next audio file.
audioPlayerDidFinishPlaying will then be called again when that one
finishes playing, and you start the next one after that, etc.

how to stop AVAudioPlayer securely

i have an AVAudioPlayer with two buttons : Play and Stop.
The play button is hidden when playing, and vice versa.
The problem is that a crash occurs when i attempt to push the Stop button, just at the end of the playing, at the moment when the method "audioPlayerDidFinishPlaying" is invoked.
Indeed, this method release the AVAudioPlayer, and when i push the stop button (which release the object too...) it crashes.
But still, i test if the player is nil before releasing it manually, so why does it crashes and how to avoid this ?
My code :
in the .h :
#private AVAudioPlayer* monPlayer;
in the .m :
-(IBAction)playSound{
NSString *path = nil;
if(path = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"sounds/%d", idoiseau] ofType:#"m4a"])
{
monPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
monPlayer.delegate = self;
[monPlayer play];
[buttonPlay setEnabled:NO];
[buttonStop setEnabled:YES];
}
else return;
}
-(IBAction)stopSound{
if(!monPlayer) return;
[monPlayer stop];
[monPlayer release];
monPlayer = nil;
[buttonPlay setEnabled:YES];
[buttonStop setEnabled:NO];
}
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
[player release];
player = nil;
[buttonPlay setEnabled:YES];
[buttonStop setEnabled:NO];
}
edit : just replace the local variable "player" by the instance variable "monPlayer" in the delegate method, and it works. Thanks to hotpaw2 :-)
Your code seems to be setting the local parameter player to nil instead of the object instance variable monPlayer.

How to prevent AVAudioPlayer from playing before a view is displayed

Hi there I have an a UIView named HomeViewController that use UINavigationController. On a click of a button, I push another view using the following code:
gameView = [[GameViewControler alloc] init];
[[self navigationController] pushViewController:gameView animated:YES];
[gameView release];
In GameViewController's viewDidLoad, I use the following code to play two audio file one after another:
//handle sound stuff
if([[GameStore defaultStore] currentIndex] == 0)
{
if(![audioPlayer isPlaying])
{
NSString *findPath = [[NSBundle mainBundle] pathForResource:#"findtheword" ofType:#"aiff"];
if(findPath)
{
NSURL *findURL = [NSURL fileURLWithPath:findPath];
NSError *findError;
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:findURL error:&findError];
if(audioPlayer == nil)
{
NSLog([findError description]);
}
else{
[audioPlayer play];
}
}
}
}
while ([audioPlayer isPlaying]) {
//do nothing and wait so the sound is not overlap
}
if(![audioPlayer isPlaying] || ([audioPlayer isPlaying] && override)){
Word *currentWord = [[GameStore defaultStore] currentWord];
NSString *soundPath = [[NSBundle mainBundle] pathForResource:[currentWord fileName]
ofType:[currentWord fileType]];
// If this file is actually in the bundle...
if (soundPath) {
// Create a file URL with this path
NSURL *soundURL = [NSURL fileURLWithPath:soundPath];
NSError *error;
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundURL error:&error];
if (audioPlayer == nil)
NSLog([error description]);
else
[audioPlayer play];
}
[FlurryAnalytics logEvent:#"GameViewController - playSound"];
}
else{
[FlurryAnalytics logEvent:#"GameViewController - playSound is still playing"];
}
I can't figure out why the first audio file started to play while the screen is still on HomeViewController even though it is being called from GameViewController's viewDidLoad.
If I remove the following code:
while ([audioPlayer isPlaying]) {
//do nothing and wait so the sound is not overlap
}
The first audio file started to play when GameViewController is loaded but the 2nd audio file overlap.
Thank you very much.
Does the audio file start to play after you click some button or table view cell in HomeViewController? As in, it starts to play while the GameViewController's view is being animated from right to left? If so, then that's because -viewDidLoad is called before the view is actually presented. What you need to do is instead place your view logic in -viewDidAppear:. That will only be called when the view is finished animating and is completely visible.
You could move the code from viewDidLoad to viewDidAppear:.

Can you see anything wrong in this code?

NSString *path = [[NSBundle mainBundle] pathForResource:[arraySub objectAtIndex:indexPathHere.row] ofType:#"mp3"];
NSURL *file = [[NSURL alloc] initFileURLWithPath:path];
AVAudioPlayer *myPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:file error:nil];
self.player = myPlayer;
[player prepareToPlay];
[player setDelegate:self];
[self.player play];
NSTimeInterval lenghtMusic = player.duration;
if (player.currentTime == lenghtMusic) {
NSLog(#"It worked");
[tableThing deselectRowAtIndexPath:indexPathHere animated:YES];
[myPlayer autorelease];
[file autorelease];
}
Can you see anything wrong?
Apparently, the "if"-statement never gets called...
If I read your code correctly you are trying to find out when the player has finished playing and then you want to deselect the current rode and release the player. Your problem is that you start the player and then immediately checks where it is currently playing. Unless you have an almost 0 length file the currentTime and length will NEVER be equal.
If that is what you are trying to do you should use the AVAudioPlayerDelegate Protocol and especially the:
– audioPlayerDidFinishPlaying:successfully:
method that is called when the player is finished.
So you need to change your class that controls the player by editing the .h file to use the AVAudioPlayerDelegate Protocol. Obviously keep extending whatever you were before.
#interface YourClass <AVAudioPlayerDelegate>
#end
In your .m file:
Then when you have created and assigned your player instance:
[player setDelegate:self];
In the .m file also add the method
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
// Your success code goes here
}
You are comparing double's with ==, which is almost always false due to round-off errors.
Compare with a range e.g.
if (fabs(player.currentTime - lenghtMusic) < 0.0001) {
...
}
I'm a noob iPhone dev, but are you sure that player.currentTime is a NSTimeInterval? That looks like the most obvious candidate.
Also, I'd log out what your player.currentTime is and what lenghtMusic is before your if and that'll probably let you know what's going on.