AVPlayer audioSessionGotInterrupted notification when waking up from background

拥有回忆 提交于 2020-08-21 18:39:47

问题


I use AVAudioPlayer to play audio. I have background audio enabled and the audio sessions are configured correctly.

I implemented the audioSessionGotInterrupted method to be informed if the audio session gets interrupted. This is my current code:

@objc private func audioSessionGotInterrupted(note: NSNotification) {

    guard let userInfo = note.userInfo,
        let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt,
        let type = AVAudioSessionInterruptionType(rawValue: typeValue) else {
            return
    }

    if type == .began {
        print("interrupted")
        // Interruption began, take appropriate actions
        player.pause()
        saveCurrentPlayerPosition()
    }
    else if type == .ended {
        if let optionsValue = userInfo[AVAudioSessionInterruptionOptionKey] as? UInt {
            let options = AVAudioSessionInterruptionOptions(rawValue: optionsValue)
            if options == .shouldResume {
                print("restored")
                // Interruption Ended - playback should resume
                setupPlayer()
                player.play()
            } else {
                // Interruption Ended - playback should NOT resume
                // just keep the player paused
            }
        }
    }
}

Now I do the following:

  • Play some audio
  • Lock the phone
  • Pause the audio
  • Wait for some seconds until I see in the XCode debugger that the app has been stopped in background
  • I hit play in the lockscreen

My commandCenter play() methods gets called as expected. However also the audioSessionGotInterrupted method gets called with type == .began.

How is that possible? I expect to see no notification of that kind or at least .ended

I use iOS 10 beta 8.


回答1:


Check this

https://developer.apple.com/documentation/avfoundation/avaudiosession/1616596-interruptionnotification

Starting in iOS 10, the system will deactivate the audio session of most apps in response to the app process being suspended. When the app starts running again, it will receive an interruption notification that its audio session has been deactivated by the system. This notification is necessarily delayed in time because it can only be delivered once the app is running again. If your app's audio session was suspended for this reason, the userInfo dictionary will contain the AVAudioSessionInterruptionWasSuspendedKey key with a value of true.

If your audio session is configured to be non-mixable (the default behavior for the playback, playAndRecord, soloAmbient, and multiRoute categories), it's recommended that you deactivate your audio session if you're not actively using audio when you go into the background. Doing so will avoid having your audio session deactivated by the system (and receiving this somewhat confusing notification).

if let reason = AVAudioSessionInterruptionType(rawValue: reasonType as! UInt) {
  switch reason {
  case .began:
    var shouldPause = true
    if #available(iOS 10.3, *) {
      if let _ = notification.userInfo?[AVAudioSessionInterruptionWasSuspendedKey] {
        shouldPause = false
      }
    }
    if shouldPause {
      self.pause()
    }
    break
  case .ended:
    break
  }
}



回答2:


While the answer above is not wrong it still caused a lot of trouble in my app and a lot of boilerplate code for checking multiple cases.

If you read the description of AVAudioSessionInterruptionWasSuspendedKey it says that the notification is thrown if you didn't deactivate your audio session before your app was sent to the background (which happens every time you lock the screen)

To solve this issue you simply have to deactivate your session if there is no sound playing when app is sent to background and activate it back if the sound is playing. After that you will not receive the AVAudioSessionInterruptionWasSuspendedKey notification.

   NotificationCenter.default.addObserver(forName: UIApplication.willResignActiveNotification, object: nil, queue: .main) { sender in
        guard self.player.isPlaying == false else { return }
        self.setSession(active: false)
    }

    NotificationCenter.default.addObserver(forName: UIApplication.didBecomeActiveNotification, object: nil, queue: .main) { sender in
        guard self.player.isPlaying else { return }
        self.setSession(active: true)
    }

func setSession(active: Bool) -> Bool {
    let session = AVAudioSession.sharedInstance()
    do {
        try session.setCategory(.playback, mode: .default)
        try session.setActive(active)
        return true
    } catch let error {
        print("*** Failed to activate audio session: \(error.localizedDescription)")
        return false
    }
}

Note: Activating session is probably not necessary because it is handled by Apple's internal playback classes (like AVPlayer for example) but it is a good practice to do it manually.



来源:https://stackoverflow.com/questions/39184859/avplayer-audiosessiongotinterrupted-notification-when-waking-up-from-background

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!