Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
398 views
in Technique[技术] by (71.8m points)

objective c - Audio session .ended isn't called with two AVPlayers

Here are steps to reproduce:

  1. Activate AVAudioSession with .playback category.
  2. Register for AVAudioSession.interruptionNotification
  3. Create two AVPlayers and start them
  4. Interrupt playback by calling Siri/receiving a call by Skype, Cellular and etc.

Expected behavior: Receiving notification of the audio session interruption with .began state at the start and .ended at the end. Also, as a side effect, Siri doesn't respond to commands.

Real behavior: Only .began notification is called.

To bring back .ended notification (which is used to continue playback) remove one player.

Question: how to handle the audio session interruption with more than 1 AVPlayer running?

Here I created a simple demo project: https://github.com/denis-obukhov/AVAudioSessionBug

Tested on iOS 14.4

import UIKit
import AVFoundation

class ViewController: UIViewController {
  private let player1: AVPlayer? = {
    $0.volume = 0.5
    return $0
  }(AVPlayer())

  private let player2: AVPlayer? = {
    $0.volume = 0.5
    return $0 // return nil for any player to bring back .ended interruption notification
  }(AVPlayer())

  override func viewDidLoad() {
    super.viewDidLoad()
    registerObservers()
    startAudioSession()
  }

  override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    player1?.replaceCurrentItem(with: makePlayerItem(named: "music1"))
    player2?.replaceCurrentItem(with: makePlayerItem(named: "music2"))
    [player1, player2].forEach { $0?.play() }
  }

  private func makePlayerItem(named name: String) -> AVPlayerItem {
    let fileURL = Bundle.main.url(
      forResource: name,
      withExtension: "mp3"
    )!
    return AVPlayerItem(url: fileURL)
  }

  private func registerObservers() {
    NotificationCenter.default.addObserver(
      self, selector: #selector(handleInterruption(_:)),
      name: AVAudioSession.interruptionNotification,
      object: nil
    )
  }

  private func startAudioSession() {
    try? AVAudioSession.sharedInstance().setCategory(.playback)
    try? AVAudioSession.sharedInstance().setActive(true)
  }

  @objc private func handleInterruption(_ notification: Notification) {
    print("GOT INTERRUPTION")
    guard
      let userInfo = notification.userInfo,
      let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt,
      let type = AVAudioSession.InterruptionType(rawValue: typeValue)
    else {
      return
    }

    switch type {
    case .began:
      print("Interruption BEGAN")
      [player1, player2].forEach { $0?.pause() }
    case .ended:
      // This part isn't called if more than 1 player is playing
      print("Interruption ENDED")
      [player1, player2].forEach { $0?.play() }
    @unknown default:
      print("Unknown value")
    }
  }
}
question from:https://stackoverflow.com/questions/66046408/audio-session-ended-isnt-called-with-two-avplayers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...