从后台唤醒时AVPlayer audioSessionGotInterrupted通知

时间:2016-08-27 19:20:58

标签: ios notifications avplayer avaudiosession

我使用AVAudioPlayer播放音频。我启用了后台音频,并且音频会话配置正确。

我实现了audioSessionGotInterrupted方法,以便在音频会话中断时被通知。这是我目前的代码:

@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
            }
        }
    }
}

现在我执行以下操作:

  • 播放一些音频
  • 锁定手机
  • 暂停音频
  • 等待几秒钟,直到我在XCode调试器中看到应用程序已在后台停止
  • 我在锁屏中玩了

我的commandCenter play()方法按预期调用。但是,使用audioSessionGotInterrupted调用type == .began方法。

怎么可能?我希望不会发现此类通知或至少.ended

我使用的是iOS 10 beta 8。

2 个答案:

答案 0 :(得分:2)

虽然上面的答案是正确的,但它仍然在我的应用程序中造成了很多麻烦,并导致了很多用于检查多种情况的样板代码。

如果您阅读了AVAudioSessionInterruptionWasSuspendedKey的说明,则说明如果未在将应用发送到后台(每次锁定屏幕时发生)之前停用音频会话,就会引发通知。

要解决此问题,您仅需在将应用发送到后台时没有声音播放时停用会话,然后在声音播放时将其激活。之后,您将不会收到AVAudioSessionInterruptionWasSuspendedKey通知。

   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
    }
}

注意:激活会话可能不是必需的,因为它由Apple的内部回放类(例如AVPlayer)处理,但是手动进行是一种很好的做法。

答案 1 :(得分:1)

检查

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

从iOS 10开始,系统将停用大多数应用程序的音频会话,以响应应用程序进程被暂停的情况。当应用再次开始运行时,它将收到一个中断通知,说明其音频会话已被系统停用。该通知必须延迟时间,因为只有在应用再次运行时才能传递该通知。如果您的应用程序的音频会话由于此原因而被暂停,则userInfo词典将包含值为true的AVAudioSessionInterruptionWasSuspendedKey键。

如果您的音频会话配置为不可混合(播放,playAndRecord,soloAmbient和multiRoute类别的默认行为),建议您在去时不积极使用音频的情况下停用音频会话进入后台。这样做可以避免您的音频会话被系统停用(并收到此令人困惑的通知)。

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
  }
}