Karthik Sivam
Karthik Sivam

Reputation: 2565

AVAudioPlayer resume audio clips from the same state after interruption

I'm using AVAudioPlayer instances in my project to play both background music clips and voice audio clips in sequence. I have to sync the audio with the animations displayed. It works great except in a scenario (i.e) after an interruption such as a call. If the interruption begins the animation will get paused , and if ends it will be resumed, audio should be in the same way so that it could be synced perfectly.

I have used delegate methods of AVAudioPlayer which get called during an interruption,

- (void) audioPlayerBeginInterruption: (AVAudioPlayer *) player {
   [self pauseAllPlayers];
}

- (void) audioPlayerEndInterruption: (AVAudioPlayer *) player withOptions:(NSUInteger) flags{
    [self playAllPlayers];
}

-(void)pauseAllPlayers
{
if(musicPlayer1)
[musicPlayer1 pause];
if(musicPlayer2)
[musicPlayer2 pause];
 // ... paused all players the similar way
}

-(void)playAllPlayers
{
if(musicPlayer1)
 [musicPlayer1 play];
// .. played all players the similar way
}

I have also set delegate to self. It works fine , but the audio clip not getting resumed from the same state after interruption, it plays the clip from the beginning. I have also tried the following:

1)

- (void)endInterruptionWithFlags:(NSUInteger)flags {
    if (flags) {
        if (AVAudioSessionInterruptionFlags_ShouldResume) {
                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1), dispatch_get_main_queue(), ^{
                   [self playAllPlayers];
                });
        }
    }
}

2)

    - (void) audioPlayerEndInterruption: (AVAudioPlayer *) player withOptions:(NSUInteger) flags{
       [NSTimer scheduledTimerWithTimeInterval:0.3 target:self selector:@selector(resumeBG) userInfo:nil repeats:NO];
      [musicPlayer1 play];
}

-(void) resumeBG
{
  [musicPlayer2 play]; // This is the player that plays background music.
}

3)

    - (void) audioPlayerBeginInterruption: (AVAudioPlayer *) player {
       [self stopAllAudioPlayers];
    }

    - (void) audioPlayerEndInterruption: (AVAudioPlayer *) player withOptions:(NSUInteger) flags{
        [self playAllPlayers];
    }

-(void) stopAllAudioPlayers
{
if(musicPlayer1)
[musicPlayer1 stop];
if(musicPlayer2)
[musicPlayer2 stop];
//...
}

But these are not working. I need to resume both BG and voice audio clips from the same state when the interruption begins. Is there a way to do that with AVAudioPlayer itself?

EDIT:

Based on Duncan C's answer I have tried the following:

    - (void) audioPlayerBeginInterruption: (AVAudioPlayer *) player {
       [self storeTime];
    }

    - (void) audioPlayerEndInterruption: (AVAudioPlayer *) player withOptions:(NSUInteger) flags{
        [self resumeAtTime];
    }

  - (void) storeTime
   {
      player1Time = [player1 currentTime];
      player2Time = [player2 currentTime];
   }
   -(void) resumeAtTime
    {
       [player1 playAtTime:player1Time];
       [player2 playAtTime:player2Time];
     }

I have also tried using (player1.deviceCurrentTime + player1Time) in resumeAtTime function. Is that the correct way to do so? Also I have tried using player.currentTime/player1.rate

Upvotes: 0

Views: 1089

Answers (1)

Duncan C
Duncan C

Reputation: 131481

The docs don't make it clear if the play method plays a sound from the beginning or continues after a pause. It just says that it plays the sound, which suggests playing from the beginning. Your findings suggest that that is what it does.

Here's what I would do. Use the currentTime method to get the playback point for your sound(s) before pausing them.

Then use playAtTime to resume each sound at the time it left off.

Upvotes: 1

Related Questions