title: Resume AVAudioPlayer after phone call not working
body: <p>There are some seemingly similar questions already on SO, but after hours of searching and experimenting with my code, I have been unable to find a clear answer. The closest thing I could find was <a href="https://stackoverflow.com/a/13840435/5225549">this answer</a> which alludes to a "known bug" 4 years ago, but does not elaborate on how to address it.</p>
  
  <p>I have an audioPlayer class that is playing an audio file with AVAudioPlayer and listening for the <code>AVAudioSessionDelegate</code> methods <code>beginInterruption</code> and <code>endInterruption</code>. I know that <code>endInterruption</code> is not guaranteed so I store a boolean in <code>beginInterruption</code> and handle restarting the audio playback in <code>applicationDidBecomeActive</code>.</p>
  
  <p>This all works perfectly as expected if the phone receives a call and the user declines it or lets it go to voicemail. As soon as my app goes back into the active state, audio playback resumes.</p>
  
  <p><strong>Here's where I'm getting weird behavior:</strong> If the user <em>answers</em> the call, once they hang up everything <em>seems</em> to work as expected but no sound comes out through either the headphones or the speakers.</p>
  
  <p>I can verify that the audio is technically <em>playing</em> by printing its volume and currentTime every second, but the sound isn't coming out.</p>
  
  <p>If I wait for 20-40 seconds, the audio suddenly cuts in and becomes audible, as if it had been silently playing in the background.</p>
  
  <p>After more debugging, I noticed that <code>AVAudioSession.sharedInstance().secondaryAudioShouldBeSilencedHint</code> remains <code>true</code> for these 20-40 seconds of silence, before suddenly changing to <code>false</code> and letting the audio play.</p>
  
  <p>I subscribed to the <code>AVAudioSessionSilenceSecondaryAudioHintNotification</code> to see if I could detect this change, but it never gets called, even when <code>.secondaryAudioShouldBeSilencedHint</code> changes from <code>true</code> to <code>false</code>.</p>
  
  <p>I even tried <em>explicitly</em> setting <code>AVAudioSession.sharedInstance().setActive(true)</code> in the method that resumes playback of the audio, but the behavior did not change.</p>
  
  <p>Lastly, I tried setting a timer to delay the resume for 10 seconds after <code>applicationDidBecomeActive</code>, but the behavior did not change.</p>
  
  <p><strong>So, why does it seem that the phone call is not relinquishing control of the audio session back to my app?</strong></p>
  
  <p>Thanks for taking a look!</p>
  
  <hr>
  
  <p>Code:</p>
  
  <p><strong>AVAudioSession setup in <code>init()</code>:</strong></p>
  
  <pre><code>NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.handleAudioHintChange), name: AVAudioSessionSilenceSecondaryAudioHintNotification, object: nil)
  NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.handleAudioInterruption), name: AVAudioSessionInterruptionNotification, object: nil)
  
  do {
    try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, withOptions: AVAudioSessionCategoryOptions.MixWithOthers)
    print("AVAudioSession Category Playback OK")
    do {
      try AVAudioSession.sharedInstance().setActive(true, withOptions: .NotifyOthersOnDeactivation)
      print("AVAudioSession is Active")
    } catch let error as NSError {
      print(error.localizedDescription)
    }
  } catch let error as NSError {
    print(error.localizedDescription)
  }
  </code></pre>
  
  <p><strong>Notification handlers:</strong></p>
  
  <pre><code>///////////////////////////////////
  // This never gets called :( //////
  
  func handleAudioHintChange(notification: NSNotification) {
    print("audio hint changed")
  }
  ///////////////////////////////////
  
  func handleAudioInterruption(notification: NSNotification) {
    if notification.name != AVAudioSessionInterruptionNotification || notification.userInfo == nil{
      return
    }
  
    if let typeKey = notification.userInfo [AVAudioSessionInterruptionTypeKey] as? UInt,
    let type = AVAudioSessionInterruptionType(rawValue: typeKey) {
      switch type {
        case .Began:
          print("Audio Interruption Began")
          NSUserDefaults.standardUserDefaults().setBool(true, forKey:"wasInterrupted")
  
        case .Ended:
          print("Audio Interuption Ended")
      }
    }
  }
  </code></pre>
  
  <p><strong>App Delegate:</strong></p>
  
  <pre><code>func applicationDidBecomeActive(application: UIApplication) {
    if(NSUserDefaults.standardUserDefaults().boolForKey("wasInterrupted")) {
      audioPlayer.resumeAudioFromInterruption()
    }
  }
  </code></pre>
  
  <p><strong>Restart function:</strong></p>
  
  <pre><code>// This works great if the phone call is declined
  func resumeAudioFromInterruption() {
    NSUserDefaults.standardUserDefaults().removeObjectForKey("wasInterrupted")
    do {
      try AVAudioSession.sharedInstance().setActive(true)
      print("AVAudioSession is Active")
    } catch let error as NSError {
      print(error.localizedDescription)
    }
    thisFunctionPlaysMyAudio()
  </code></pre>
  
  <p>}</p>