7

I have the following code:

AVPlayerItem *currentItem = [AVPlayerItem playerItemWithURL:soundURL];
[self.audioPlayer replaceCurrentItemWithPlayerItem:currentItem];
[self.audioPlayer play];

where soundURL is a remoteURL. It works fine. The AVPlayer plays the music perfectly. I have a progress bar and i am updating it based on the current time of the player.

Everything works fine. My issue is when i drag the progress bar forward the audioplayer starts from the new location but if i drag the progressbar it doesn't start from the new location in fact it resumes from the previous location. Here is my progress bar drag start and stop code:

- (IBAction)progressBarDraggingStart:(id)sender
{
     if (self.audioPlayer.rate != 0.0)
     {
          [self.audioPlayer pause];
     }
}

- (IBAction)progressBarDraggindStop:(id)sender
{
     CMTime newTime = CMTimeMakeWithSeconds(self.progressBar.value, 1);
     [self.audioPlayer seekToTime:newTime];
     [self.audioPlayer play];
}

Can anyone help me fix this issue?

Anand Y
  • 329
  • 2
  • 13
  • Have you tried using `seekToTime:completionHandler:` or `seekToTime:toleranceBefore:toleranceAfter:`? – Corey Feb 24 '14 at 16:08
  • @corey: Yes i tried both of them but no luck. The completionHandler finished flag is returning false. Do you know how to keep waiting until the finished flag in the completion handler becomes true? – Anand Y Feb 24 '14 at 16:19

2 Answers2

8

I suggest doing a couple of things. First, get the timescale value and pass it to the CMTime struct. Second, use the seekToTime:toleranceBefore:toleranceAfter:completionHandler: method for more accurate seeking. For example, your code would look like:

- (IBAction)progressBarDraggindStop:(id)sender {
    int32_t timeScale = self.audioPlayer.currentItem.asset.duration.timescale;

    [self.audioPlayer seekToTime: CMTimeMakeWithSeconds(self.progressBar.value, timeScale)
                 toleranceBefore: kCMTimeZero
                  toleranceAfter: kCMTimeZero
               completionHandler: ^(BOOL finished) {
                   [self.audioPlayer play];
               }];
}
Corey
  • 5,818
  • 2
  • 24
  • 37
  • i've used your code just now and got the following exception - "*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Seeking is not possible to time {INVALID}'" – Anand Y Feb 24 '14 at 16:25
  • What is the `timeScale` value that you get? Also, try logging the `self.progressBar.value` and the `CMTimeMakeWithSeconds` value. – Corey Feb 24 '14 at 16:29
  • Here are the values: Timescale = 0, Progressbar Value = 281.286560, CMTIme = (null) – Anand Y Feb 24 '14 at 16:32
  • 1
    i found out that there was nothing wrong with my code. The URL that i used in the AVPlayeItem is actually a web service call. The guys who coded the webservice weren't passing the required headers that's why the AVPlayer couldn't even get the duration. Today our guys fixed the webservice side and now my seekToTime: method works perfectly. – Anand Y Mar 05 '14 at 22:21
  • @AnandY I am running into the same problem as you, can you provide the documentation that you found on what headers AVPlayerItem requires? – MweyaMutsvene Aug 26 '14 at 09:00
  • 2
    @MweyaMutsvene : These are the two important header fields: Content-Length:(byte count of the data in the response) and Content-Range:(bytes 0-1/size of the file). Let me know if it works for you or not. – Anand Y Aug 28 '14 at 16:22
  • Voted up for the `completionHandler` :) – atulkhatri Sep 02 '15 at 06:49
  • @AnandY Argh! Thanks so much for following up re: headers. Turns out that was my problem as well. Took all day to find the cause! – Illya Moskvin Mar 16 '17 at 22:07
1

I am using below code for dragging- Added completionHandler after @Corey's answer and it works great without any web-service dependency:

- (void) sliderValueChanged:(id)sender {
    if ([sender isKindOfClass:[UISlider class]]) {
        UISlider *slider = sender;

        CMTime playerDuration = self.avPlayer.currentItem.duration;
        if (CMTIME_IS_INVALID(playerDuration)) {
            return;
        }

        double duration = CMTimeGetSeconds(playerDuration);
        if (isfinite(duration)) {
            float minValue = [slider minimumValue];
            float maxValue = [slider maximumValue];
            float value = [slider value];

            double time = duration * (value - minValue) / (maxValue - minValue);

            [self.avPlayer seekToTime:CMTimeMakeWithSeconds(time, NSEC_PER_SEC) toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero completionHandler:^(BOOL finished) {
                [self.avPlayer play];
            }];
        }
    }
}
atulkhatri
  • 10,896
  • 3
  • 53
  • 89