How to stop an avaudioplayer playing previous song while clicking on newsong? - ios

I created a view with a button songs.
When we click on button it goes to a table which contains list of songs.
When we select a song it goes to another view and plays the song.
Whenever the song is playing we can go back to main view or to the table of songs the song will be playing in background its fine upto here.
But whenever I try to play another song from the table of songs the previous song is not stopped and it continues to play along with the selected song.
My aim is play the song when it is switched to a different view. I have done this one but what I want is whenever I select another song from the table of songs it must stop the previous song and play the selected song.
-(void)playOrPauseButtonPressed:(id)sender
{
[self.view addSubview:today_slokaText];
if(playing==NO)
{
[UIApplication sharedApplication].networkActivityIndicatorVisible=YES;
[playButton setBackgroundImage:[UIImage imageNamed:#"Pause.png"] forState:UIControlStateNormal];
[self.view addSubview:today_slokaText];
// Here Pause.png is a image showing Pause Buttomn
NSError *err=nil;
if (!audioPlayer)
{
[self loadSongAtIndex: selectedIndex];
playing=YES;
}
audioPlayer.numberOfLoops = 0;
[audioPlayer prepareToPlay];
[audioPlayer play];
audioPlayer.delegate=self;
if(!audioPlayer.playing)
{
[audioPlayer play];
activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
[self.view addSubview:self.activityIndicator];
self.activityIndicator.center = CGPointMake(self.view.frame.size.width / 2, self.view.frame.size.height / 2);
[self.activityIndicator startAnimating];
[playButton setBackgroundImage:[UIImage imageNamed:#"Pause.png"] forState:UIControlStateNormal];
[bg_Image addSubview:activityIndicator];
}
playing=YES;
}
else if (playing==YES)
{
[self.activityIndicator stopAnimating];
self.activityIndicator.alpha=0.0;
// [bg_Image addSubview:activityIndicator];
[playButton setBackgroundImage:[UIImage imageNamed:#"play12.png"] forState:UIControlStateNormal];
[self.view addSubview:today_slokaText];
[audioPlayer pause];
playing=NO;
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateViewForPlayerState) userInfo:nil repeats:YES];
[self.view addSubview:today_slokaText];
}
}
/******************************************
load the song from service
*******************************************/
- (void)loadSongAtIndex:(NSInteger) songIndex
{
audioSession=[AVAudioSession sharedInstance];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
urlsArray=[[NSMutableArray alloc]initWithObjects:#"http://01_ARDHANAREESWARASTOTRAM.mp3",#"http://02_AshtaLakshmiStotram.mp3",#"http://03_AYIGIRINANDININANDITHAMEDINI.mp3",, nil];
NSString *sourcePath = [urlsArray objectAtIndex:songIndex];
NSURL *audioURL=[NSURL URLWithString:sourcePath];
NSData *data=[NSData dataWithContentsOfURL:audioURL];
audioPlayer = [[AVAudioPlayer alloc] initWithData:data error:NULL];
audioPlayer.numberOfLoops = 0;
[audioPlayer prepareToPlay];
[audioPlayer play];
audioPlayer.delegate=self;
if(!audioPlayer.playing)
{
[audioPlayer play];
}
if (self.audioPlayer)
{
[self updateViewForPlayerInfo];
[self updateViewForPlayerState];
[self.audioPlayer setDelegate:self];
}
}

You are creating the instance of your audio player everytime you load a song from the table. This creates multiple instances. So whenever you play a song it will be played in the new audio player instance and the previous songs(with different audio player instances) will also keep playing. So what i suggest is that you should create audio player at the class level and not create instances everytime. This will hold the single instance and will play a single song for you.

Related

Toggle play/pause button with loop playback

I have a button that toggles between a play and a pause image when tapped. When play image is shown a looped sound is playing, when pause image is shown sound stops playing.
I have manage to get this to work, but there is one issue. When you tap the button to pause (stop) it plays the sound one last time (so the pause action is delayed by the number of seconds of the sound).
Here's my code:
#implementation ViewController
AVAudioPlayer *myAudio;
- (void)viewDidLoad {
[super viewDidLoad];
[self.myButton setImage:[UIImage imageNamed:#"play.png"] forState:UIControlStateNormal];
[self.myButton setImage:[UIImage imageNamed:#"pause.png"] forState:UIControlStateSelected];
}
- (IBAction)buttonTapped:(id)sender {
NSURL *musicFile;
musicFile = [NSURL fileURLWithPath: [[NSBundle mainBundle] pathForResource:#"sound" ofType:#"mp3"]];
myAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:musicFile error:nil];
if(self.myButton.selected)
[self.myButton setSelected:NO];
else
[self.myButton setSelected:YES];
if(self.myButton.selected)
[myAudio setNumberOfLoops:-1];
[myAudio play];
}
What you're doing is creating a player every time you tap on the button.
You should try and create one AVPlayer (in viewDidLoad), and use it's play and pause functions in the buttonTapped: function.
- (void)viewDidLoad {
[super viewDidLoad];
[self.myButton setImage:[UIImage imageNamed:#"play.png"] forState:UIControlStateNormal];
[self.myButton setImage:[UIImage imageNamed:#"pause.png"] forState:UIControlStateSelected];
NSURL *musicFile = [NSURL fileURLWithPath: [[NSBundle mainBundle] pathForResource:#"sound" ofType:#"mp3"]];
myAudio = [[AVAudioPlayer alloc] initWithContentsOfURL:musicFile error:nil];
}
- (IBAction)buttonTapped:(id)sender {
[self.myButton setSelected:!self.myButton.selected];
if (self.myButton.selected) {
[player seekToTime:kCMTimeZero];
[player play];
}
else {
[player pause];
}
}
Clicking on the button would first toggle it's state (selected or not) and then based on its state, the player will rewind and start playing, or pause itself (instantly).

Get AVAudioPlayer delegate audioPlayerDidFinishPlaying when app was in background [duplicate]

So I have an app that plays a bunch of songs while the user can flip through a comic book. I use AVAudioPlayer and I have it set up to play the songs in a set order. So when one song finishes, the next one will play. This works flawlessly when the app is open. The problem occurs when the app is in the background. I set up the app to play in the background, and that works fine. So when the user presses the home screen the music continues to play. The problem occurs when the song ends, it is suppose to play the next song like it does when the app is open. Instead nothing happens. According to the my NSLog statements the correct methods are being called but nothing happens. Here is my code:
- (void)audioPlayerDidFinishPlaying: (AVAudioPlayer *)player successfully: (BOOL) flag {
NSLog(#"Song finished");
if ([songSelect isEqualToString: #"01icecapades"]) {
isPlay = #"yes";
songSelect = #"02sugarcube";
imageSelect = #"playbanner02";
[self performSelector:#selector(triggerSong) withObject:nil afterDelay:0];
[self performSelector:#selector(triggerBanner) withObject:nil afterDelay:0];
}
else if ([songSelect isEqualToString: #"02sugarcube"]) {
isPlay = #"yes";
songSelect = #"03bullets";
imageSelect = #"playbanner03";
[self performSelector:#selector(triggerSong) withObject:nil afterDelay:0];
[self performSelector:#selector(triggerBanner) withObject:nil afterDelay:0];
}
else if ([songSelect isEqualToString: #"03bullets"]) {
isPlay = #"yes";
songSelect = #"04satanama";
imageSelect = #"playbanner04";
[self performSelector:#selector(triggerSong) withObject:nil afterDelay:0];
[self performSelector:#selector(triggerBanner) withObject:nil afterDelay:0];
}
else if ([songSelect isEqualToString: #"04satanama"]) {
isPlay = #"yes";
songSelect = #"05uglyjoke";
imageSelect = #"playbanner05";
[self performSelector:#selector(triggerSong) withObject:nil afterDelay:0];
[self performSelector:#selector(triggerBanner) withObject:nil afterDelay:0];
}
else if ([songSelect isEqualToString: #"05uglyjoke"]) {
isPlay = #"yes";
songSelect = #"01icecapades";
imageSelect = #"playbanner01";
[self performSelector:#selector(triggerSong) withObject:nil afterDelay:0];
[self performSelector:#selector(triggerBanner) withObject:nil afterDelay:0];
}}
Above is the code that recognizes which song is playing, and sets the correct song next. Then it triggers another method that sets up the player.
- (void)triggerSong {
NSLog(#"triggerSong called");
NSString *path;
NSError *error;
// Path the audio file
path = [[NSBundle mainBundle] pathForResource:songSelect ofType:#"mp3"];
// If we can access the file...
if ([[NSFileManager defaultManager] fileExistsAtPath:path])
{
// Setup the player
player = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error];
//player = [initWithContentsOfURL:[NSURL fileURLWithPath:path] error:&error];
[player setDelegate: self];
// Set the volume (range is 0 to 1)
player.volume = 1.0f;
[player prepareToPlay];
[player setNumberOfLoops:0];
[player play];
NSLog(#"player play");
[error release];
player.delegate = self;
// schedules an action every second for countdown
[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:#selector(updateTimeLeft) userInfo:nil repeats:YES];
}}
Now I assuming this is not the best way to do this, but it works great when the app is in the foreground state. I've been looking through the documentation and I can't seem to find the cause of this problem. I was hoping somebody might be able to see an error to my approach. Like I said before, the two NSLogs in the triggerSong method are being called so I can't see why the AVAudioPlayer (player) is not being called.
Also I have the correct setting in my info.plist and I have this in my viewDidLoad:
//Make sure the system follows our playback status
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];
Thanks for any insight. Much appreciated.
Relevant discussion
SHORT ANSWER:
You need this code in either your first view controller's init or viewDidLoad method:
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
LONG ANSWER W/ SAMPLE:
Here is my example. Like you, I began with an app that would play music in the background but could never continue playing after the first clip ended. I made a copy of the original Music.mp3 and named it Music2.mp3. My intention was to play Music2.mp3 as soon as Music.mp3 ended (audioPlayerDidFinishPlaying:). I goofed around with the background tasks for awhile until I got this working WITHOUT the background task:
-(id)init{
self = [super initWithNibName:#"MediaPlayerViewController" bundle:nil];
if(self){
//Need this to play background playlist
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
//MUSIC CLIP
//Sets up the first song...
NSString *musicPath = [[NSBundle mainBundle] pathForResource:#"Music" ofType:#"mp3"];
if(musicPath){
NSURL *musicURL = [NSURL fileURLWithPath:musicPath];
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:musicURL error:nil];
[audioPlayer setDelegate:self];
}
}
return self;
}
-(IBAction)playAudioFile:(id)sender{
if([audioPlayer isPlaying]){
//Stop playing audio and change test of button
[audioPlayer stop];
[sender setTitle:#"Play Audio File" forState:UIControlStateNormal];
}
else{
//Start playing audio and change text of button so
//user can tap to stop playback
[audioPlayer play];
[sender setTitle:#"Stop Audio File" forState:UIControlStateNormal];
}
}
-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{
[audioButton setTitle:#"Play Audio File" forState:UIControlStateNormal];
[playRecordingButton setTitle:#"Play Rec File" forState:UIControlStateNormal];
//PLAY THE SECOND SONG
NSString *musicPath2 = [[NSBundle mainBundle] pathForResource:#"Music2" ofType:#"mp3"];
if(musicPath2){
NSURL *musicURL2 = [NSURL fileURLWithPath:musicPath2];
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:musicURL2 error:nil];
[audioPlayer setDelegate:self];
NSLog(#"Play it again: \n%#", musicPath2);
[audioPlayer play];
}
}
The end result is that my app is now playing Music2.mp3 on a continuous loop, even if the app is in the background.
Just to confirm what Squatch said, this is also the solution in Swift:
UIApplication.sharedApplication().beginReceivingRemoteControlEvents()
OS X exhibits the same problem using AVAudioPlayer, however UIApplication is an iOS-only construct. OS X requires using NSApplication instead, but NSApplication doesn't return until the application is terminating so we need to use threads. As a bonus, there's an assert() somewhere in the depths of NSApplication that demands the main thread.
This hybrid C++/Objective C function is one workaround for this OS X issue:
void do_the_dumb (void real_application(void)) {
std::thread thread ([real_application]() {
real_application();
[[NSApplication sharedApplication] terminate: [NSApplication sharedApplication]];
});
[[NSApplication sharedApplication] run];
thread.join();
};

In song loading time how to display activity indicator if user click the play button in iPhone using AVAudioplayer

I am working in AVAudioplayer in iOS. I am displaying an activity indicator for loading time if a user clicks the play button. My problem is that when I click the play button the loading time activity indicator is not displayed. In playing time activity indicator displayed that is my problem.
-(void)viewDidLoad
{
// loading View
loadingView=[[UILabel alloc]initWithFrame:CGRectMake(135, 200, 40, 40)];
loadingView.backgroundColor=[UIColor whiteColor];
loadingView.clipsToBounds=YES;
loadingView.layer.cornerRadius=10.0;
activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
activityView.frame = CGRectMake(10, 11, activityView.bounds.size.width, activityView.bounds.size.height);
[loadingView addSubview:activityView];
}
-(void)playOrPauseButtonPressed:(id)sender
{
if(playing==NO)
{
[UIApplication sharedApplication].networkActivityIndicatorVisible=YES;
[self.view addSubview:loadingView];
[activityView startAnimating];
[playButton setBackgroundImage:[UIImage imageNamed:#"Pause.png"] forState:UIControlStateNormal];
// Here Pause.png is a image showing Pause Button.
NSError *err=nil;
AVAudioSession *audioSession=[AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
NSLog(#"%# %d",urlsArray,selectedIndex);
NSString *sourcePath=[urlsArray objectAtIndex:selectedIndex];
NSData *objectData=[NSData dataWithContentsOfURL:[NSURL URLWithString:sourcePath]];
audioPlayer = [[AVAudioPlayer alloc] initWithData:objectData error:&err];
if(err)
{
NSLog(#"Error %ld,%#",(long)err.code,err.localizedDescription);
}
NSTimeInterval bufferDuration=0.005;
[audioSession setPreferredIOBufferDuration:bufferDuration error:&err];
if(err)
{
NSLog(#"Error %ld, %#", (long)err.code, err.localizedDescription);
}
double sampleRate = 44100.0;
[audioSession setPreferredSampleRate:sampleRate error:&err];
if(err)
{
NSLog(#"Error %ld, %#",(long)err.code,err.localizedDescription);
}
[audioSession setActive:YES error:&err];
if(err)
{
NSLog(#"Error %ld,%#", (long)err.code, err.localizedDescription);
}
sampRate=audioSession.sampleRate;
bufferDuration=audioSession.IOBufferDuration;
NSLog(#"SampeRate:%0.0fHZI/OBufferDuration:%f",sampleRate,bufferDuration);
audioPlayer.numberOfLoops = 0;
[audioPlayer prepareToPlay];
audioPlayer.delegate=self;
if(!audioPlayer.playing)
{
[audioPlayer play];
}
playing=YES;
}
else if (playing==YES)
{
[playButton setBackgroundImage:[UIImage imageNamed:#"play.png"] forState:UIControlStateNormal];
[audioPlayer pause];
playing=NO;
}
if (self.audioPlayer)
{
[self updateViewForPlayerInfo];
[self updateViewForPlayerState];
[self.audioPlayer setDelegate:self];
}
}
First know the concept on activity indicator before start to implement. Thats good attitude for us.
http://www.ioscreator.com/tutorials/display-an-activity-indicator
use the activity indicator to display a loading process connect the activity indicator to IBOutlet and synthesize in h file and code like this
declare like this in m file
#interface updatepoliticalViewController : UIViewController
{
UIActivityIndicatorView *spinner;
}
and synthesize spinner into ur h file this difenlty work
-(void)temp
{
spinner = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
spinner.frame = CGRectMake(0.0, 0.0, 40.0, 40.0);
[spinner setCenter:CGPointMake(160, 240)];
[self.view addSubview:spinner];
spinner.color = [UIColor blueColor];
spinner.backgroundColor = [UIColor colorWithWhite:0.2 alpha:0.4];
[spinner startAnimating];
[spinner release];
}
use this method to stop the activity
-(void) myMethod{
[spinner stopAnimating];
spinner.hidden = YES;
}
call this function in view didload and specify how long u want to display the loading process
- (void)viewDidLoad
{
[super viewDidLoad];
[self temp];
[self performSelector:#selector(myMethod) withObject:nil afterDelay:5.0f];
}
hope it helps for you

how to play audioplayer in ios using AVAudioplayer

I am trying to create AVAudioPlayer Programatically.I Have small issue if i play audioplayer.
I am displaying 12 audio items in UITableview.If i click first item that corresponding song will play.I should not click any pass button.i click back button and click second item.if i click second item the audio view controller will display.I click play button the song display.In first song and second song play simultaneously.This is my issue.Please help me anybody.
-(void)playOrPauseButtonPressed:(id)sender
{
if(playing==NO)
{
[playButton setBackgroundImage:[UIImage imageNamed:#"Pause.png"] forState:UIControlStateNormal];
// Here Pause.png is a image showing Pause Button.
NSError *err=nil;
AVAudioSession *audioSession=[AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
NSLog(#"%# %d",urlsArray,selectedIndex);
NSString *sourcePath=[urlsArray objectAtIndex:selectedIndex];
NSData *objectData=[NSData dataWithContentsOfURL:[NSURL URLWithString:sourcePath]];
audioPlayer = [[AVAudioPlayer alloc] initWithData:objectData error:&err];
audioPlayer.numberOfLoops = 0;
[audioPlayer prepareToPlay];
audioPlayer.delegate=self;
[audioPlayer play];
playing=YES;
}
else if (playing==YES)
{
[playButton setBackgroundImage:[UIImage imageNamed:#"play.png"] forState:UIControlStateNormal];
[audioPlayer pause];
playing=NO;
}
if (self.audioPlayer)
{
[self updateViewForPlayerInfo];
[self updateViewForPlayerState];
[self.audioPlayer setDelegate:self];
}
}
-(void)updateViewForPlayerInfo
{
self.songDuration.text = [NSString stringWithFormat:#"%d:%02d", (int)self.audioPlayer.duration / 60, (int)self.audioPlayer.duration % 60, nil];
NSLog(#"%f", self.audioPlayer.duration);
self.progressBar.maximumValue = self.audioPlayer.duration;
self.volumeSlider.value = self.audioPlayer.volume;
}
-(void)updateViewForPlayerState
{
[self updateCurrentTime];
if (self.updatedTimer)
{
[self.updatedTimer invalidate];
}
if (self.audioPlayer.playing)
{
self.updatedTimer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:#selector(updateCurrentTime) userInfo:self.audioPlayer repeats:YES];
}
}
-(void)updateCurrentTime
{
//NSLog(#"self.audioPlayer.currentTime = %f", self.audioPlayer.currentTime);
self.currentTime.text = [NSString stringWithFormat:#"%d:%02d", (int)self.audioPlayer.currentTime / 60, (int)self.audioPlayer.currentTime % 60, nil];
self.progressBar.value = self.audioPlayer.currentTime;
}
-(void)volumeSliderMoved:(UISlider *)sender
{
self.audioPlayer.volume=[sender value];
}
before creating a new instance of AVAudioPlayer, deallocate or nil the existing instance of player by using following lines
sourcePath=Nil;
[audioPlayer stop];
audioPlayer = Nil;
Stop the player when you go back. Maybe in ViewWillDisappear or before you create a new instance of audioplayer, you can call
if(self.audioplayer) {
[self.audioPlayer stop];
self.audioPlayer = nil;
}
Before initializing the AVAudioPlayer remove all the instances that are running before.
//YOUR STUFF
NSString *sourcePath=[urlsArray objectAtIndex:selectedIndex];
NSData *objectData=[NSData dataWithContentsOfURL:[NSURL URLWithString:sourcePath]];
for (AVAudioPlayer *a in urlsArray)
[a stop];
audioPlayer = [[AVAudioPlayer alloc] initWithData:objectData error:&err];
audioPlayer.numberOfLoops = 0;
//REST STUFF

How to display Pause Button if user click the Play button in AVAudioPlayer in ios

Hi i am developing AVAudioplayer according to my project requirement.I am creating audioplayer programatically. I want to display pause button if user clicks the play button.I wrote some code.But pause button should not displayed if i click the play button.so please help me anybody. Thanks in advance.
-(void)viewDidLoad
{
playButton=[[UIButton alloc]init];
playButton.frame=CGRectMake(125, 120, 29, 29);
playButton.backgroundColor=[UIColor clearColor];
playbackgroundImage=[UIImage imageNamed:#"play.png"];
[playButton setImage:playbackgroundImage forState:UIControlStateNormal];
[playButton addTarget:self action:#selector(playOrPauseButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:playButton];
}
-(void)playOrPauseButtonPressed:(id)sender
{
if(playing==NO)
{
[playButton setBackgroundImage:[UIImage imageNamed:#"Pause.png"] forState:UIControlStateNormal];
// Here Pause.png is a image showing Pause Button.
NSError *err;
AVAudioSession *audioSession=[AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
NSData *data=[NSData dataWithContentsOfURL:url];
audioPlayer=[[AVAudioPlayer alloc]initWithData:data error:&err];
[audioPlayer prepareToPlay];
audioPlayer.delegate=self;
[audioPlayer play];
playing=YES;
}
else if (playing==YES)
{
[playButton setBackgroundImage:[UIImage imageNamed:#"play.png"] forState:UIControlStateNormal];
[audioPlayer pause];
playing=NO;
}
}
The problem is that you are setting Setimage first time and on playOrPauseButtonPressed you are setting SetBackgroundImage.
so replace this method in viewDidLoad
[playButton setBackgroundImage:playbackgroundImage forState:UIControlStateNormal];

Resources