Abirami Bala
Abirami Bala

Reputation: 790

Pause/ Play Audio Player with NSTimer iOS Objective C

I am developing an Music player App. And using Play/Pause button and a Progress bar while playing an audio. and I am calling a method with NSTimer to update progress bar. What I need is to pause the progress bar and resume it where it was left off.

I can pause the timer as well the progress bar with the code referred from the links: 1. How to pause a NSTimer? 2. How to Pause/Play NSTimer?

But I am struggling in resuming it where ii was left off. I also need to update progress bar based on the audio.

My code is as below:

AVAudioPlayer *audioPlayer;
NSTimer *audioTimer;
BOOL play;

BOOL ispaused;
int seconds1;
int minutes1;
int hours1;

NSDate *pauseStart, *previousFireDate;

Play/Pause Button action:

- (IBAction)playSoundTapped:(id)sender
{
songUrl = [NSURL URLWithString:@"http://www.stephaniequinn.com/Music/Allegro%20from%20Duet%20in%20C%20Major.mp3"];

self.playerItem = [AVPlayerItem playerItemWithURL:songUrl];
self.player = [AVPlayer playerWithPlayerItem:self.playerItem];
self.player = [AVPlayer playerWithURL:songUrl];

if (play==YES)
{
    if (ispaused == YES)
    {
        float pauseTime = -1*[pauseStart timeIntervalSinceNow];
        [audioTimer setFireDate:[NSDate dateWithTimeInterval:pauseTime sinceDate:previousFireDate]];
        audioTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(updateProgress) userInfo:nil repeats:YES];

        [self.player play];

        ispaused = NO;
    }
    else
    {
        audioTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(updateProgress) userInfo:nil repeats:YES];

        [self.player play];

        ispaused = NO;
    }

    _playImg.image=[UIImage imageNamed:@"Pause.png"];
    play=NO;
}
else
{
    [self.player pause];

    ispaused = YES;

    pauseStart = [NSDate dateWithTimeIntervalSinceNow:0];
    previousFireDate = [audioTimer fireDate];
    [audioTimer setFireDate:[NSDate distantFuture]];

    _playImg.image=[UIImage imageNamed:@"Play.png"];
    play=YES;
}
}

Updates ProgressBar:

- (void)updateProgress
{
    if (ispaused == NO)
    {
        seconds1 += 1;

    if (seconds1 == 60)
    {
        seconds1 = 0;
        minutes1++;

        if (minutes1 == 60)
        {
            minutes1 = 0;
            hours1++;
        }
    }

    float duration = CMTimeGetSeconds([_playerItem duration]);
    float actDuration = duration/100;
    float currentTime = CMTimeGetSeconds([_player currentTime]);
    float minutes = currentTime/60;
    //float seconds = (currentTime - minutes) * 60;
    NSLog(@"Duration: %.2f",actDuration);
    NSLog(@"Current Time: %.2f",minutes);

    NSString *durStr = [NSString stringWithFormat: @"%f",duration];

    if ([durStr  isEqual: @"nan"])
    {
        NSLog(@"Nan");
    }
    else
    {
        [self setProgress:minutes animated:YES];
    }
}
else
{
      NSLog(@“Paused”);        
}
}

It is restarting the audio instead of resuming. As I am a beginner to iOS I don’t know where I'm doing mistake. Can Anyone help me please….?

Upvotes: 3

Views: 1278

Answers (2)

Abirami Bala
Abirami Bala

Reputation: 790

I got it!

i just add the below in pause function

rate = CMTimeGetSeconds([_player currentTime])/60;

and setting it as a current time to the audio player with the reference from ketan Parmer's Answer

[audioPlayer setCurrentTime:rate];

and when stoping

rate = 0.0;

and rate is a float which is globally declared. Thanks to Ketan..!

Upvotes: 1

Ketan Parmar
Ketan Parmar

Reputation: 27448

What i am doing in my one of project,

 - (void)playPauseAudio : (UIButton*)sender{

if (!playPause.selected) {


    [audioPlayer play];

    sliderTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateSlider) userInfo:nil repeats:YES];
    [mySlider addTarget:self action:@selector(sliderChanged:) forControlEvents:UIControlEventValueChanged];
    mySlider.maximumValue = audioPlayer.duration;

}
else{

    [audioPlayer pause];
    [sliderTimer invalidate];
}



playPause.selected = !playPause.selected;

}

I have common button for play and pause, it just change it's title on normal state and selected state to play and pause respectively.

So in my method, playPause is button, audioPlayer is AVAudioPlayer object, sliderTimer is NSTimer object, mySlider is UISlider object to show progress. That's it. You can manage your case some how as i mentioned.

And updateSlider and sliderChanged method is something like below,

 - (void)updateSlider{

mySlider.value = audioPlayer.currentTime;
timerLabel.text = [self timeFormatted:audioPlayer.duration - audioPlayer.currentTime];
NSLog(@"update slider call");

}

- (void)sliderChanged : (UISlider*) sender{


[audioPlayer setCurrentTime:mySlider.value];
timerLabel.text = [self timeFormatted:audioPlayer.duration - mySlider.value];


}

So, If user manually change UISlider then sliderChanged will get called and your player will reach at that point.

Upvotes: 2

Related Questions