I am using Xamarin so this is C# but the following code is working for me. I first set that my AppDelegate implements the AVAudioSession delegate methods by including IAVAudioSessionDelegate
public partial class AppDelegate: UIApplicationDelegate, IAVAudioSessionDelegate
I added a variable to the AppDelegate class for the audio session
public static AVAudioSession AudioSession;
In the override of the FinishedLaunching method:
AudioSession = AVAudioSession.SharedInstance();
AudioSession.Delegate = this;
error = AudioSession.SetCategory( AVAudioSessionCategory.Playback, AVAudioSessionCategoryOptions.DuckOthers );
AudioSession.SetMode( new NSString( "AVAudioSessionModeMoviePlayback" ), out error );
The two relevant delegate methods in AppDelegate.cs are:
[Export( "beginInterruption" )]
public void BeginInterruption()
{
PlayerViewController.BeginSessionInterruption();
}
[Export( "endInterruptionWithFlags:" )]
public void EndInterruption( AVAudioSessionInterruptionFlags flags )
{ // ignore the flags so we're not dependent on the interrupting event saying that we can resume
PlayerViewController.ResumeAfterSessionInterruption();
}
My AppDelegate also has an override of OnActivated to enable the video tracks if it's a video asset, and an override of DidEnterBackground to disable the media's video tracks but still play the audio.
In the PlayerViewController.BeginSessionInterruption() method, I can't look at Player.Rate to see if the player was running at the time, because the interrupting alarm or phone call has already paused the player. From the "Responding to Interruptions" section of Apple's Audio Session Programming Guide, with my emphasis added:
- Your app is active, playing back audio.
- A phone call arrives. The system activates the phone app’s audio session.
- The system deactivates your audio session. At this point, * playback in your app has stopped *.
- The system invokes your interruption listener callback function indicating that your session has been deactivated.
...
My PlayerViewController's Play button has a Paused property to toggle between Play and Pause and draw the appropriate button image. So instead of checking Player.Rate, I look to see if the button's Paused property is false:
public void BeginSessionInterruption()
{
PlayerWasRunningOnInterruption = !btnPlay.Paused;
TogglePlayPause( true ); // put the Play button into the Paused state to agree with the player being stopped
public void ResumeAfterSessionInterruption()
{
NSError error;
AppDelegate.AudioSession.SetActive( true, AVAudioSessionSetActiveOptions.NotifyOthersOnDeactivation, out error ); // always reactivate the audio session
if ( PlayerWasRunningOnInterruption )
{
// rewind a little bit
// call btnPlayClick to resume the playback as if the user pressed the Play button
}
}