【问题标题】:Playing instance of AVAudioPlayer from background thread sometimes fails从后台线程播放 AVAudioPlayer 实例有时会失败
【发布时间】:2019-10-17 13:20:38
【问题描述】:

我正在尝试使用 Swift 5 中的 AVAudioPlayer 实例从后台线程播放声音。大多数情况下,它会成功。但有时音频播放器无法播放声音。

似乎调用 play() 两次,或者连续调用 prepareToPlay() 然后 play() 以某种方式解决了问题,但这对我来说似乎不是一个好的解决方案,因为我担心这仍然不保证会成功播放。

func setUpAudio() {
    AVAudioSession.sharedInstance().perform(NSSelectorFromString("setCategory:error:"), with: AVAudioSession.Category.playback)
    try! AVAudioSession.sharedInstance().setActive(true)
    NotificationCenter.default.addObserver(self, selector: #selector(handleInterruption), name: AVAudioSession.interruptionNotification, object: nil)
}

func startNewAudio() {
    let destinationData = Destinations.getDestinations()
    var audio = destinationData[currentStop]!["audio"] as! String
    if inTransit {
        audio = destinationData[Paths.tourOrder[currentIndex + 1]]!["transit_audio"] as! String
    }
    let sound = NSURL(fileURLWithPath: Bundle.main.path(forResource: audio, ofType: "mp3", inDirectory: "audio")!)
    try! audioPlayer = AVAudioPlayer(contentsOf: sound as URL)
    audioPlayer.delegate = self
    currentTime = 0
    setPlay()
}

func setPlay() {
    paused = false
    pauseButton.setImage(UIImage(named: "pause"), for: .normal)
    pauseButton.isEnabled = true
    audioPlayer.currentTime = currentTime
    DispatchQueue.global(qos: .background).async {
        self.audioPlayer.play()
        print(self.audioPlayer.isPlaying) // returns false sometimes
    }
}

我按以下顺序调用方法:

setUpAudio()
startNewAudio()
setPlay()

我不知道问题所在——我真的想只调用一次 play() 并让一切正常。

【问题讨论】:

  • “使用 Swift 5 中的 AVAudioPlayer 实例从后台线程播放声音。”为什么?只是不要那样做,一切都会好起来的。
  • 你的意思是我为什么要从后台线程播放它?老实说,我实际上不确定从后台线程播放它是否确实有益,但我认为它是。后台播放不会释放主线程吗?
  • 声音是异步播放的。仅在主线程上与玩家交谈。
  • 好的,太棒了,感谢您的反馈。我在这里看到了一些在后台调用 play() 的帖子。任何想法为什么?无论如何,我仍然很好奇为什么在这种情况下调用 play() 有时不起作用......

标签: ios swift avaudioplayer dispatch-queue ios-multithreading


【解决方案1】:

没有理由在后台线程上说play;播放声音不会阻塞主线程。此外,没有理由假设 AVAudioPlayer 是线程安全的。而且您的代码肯定不是线程安全的,因为您同时从不同的线程与音频播放器交谈。所以你错误地使用了线程。讨论错误的行为结果是没有意义的。拿走你的后台线程并尝试你的代码以正确的方式做事。如果还有问题我们可以讨论。

【讨论】:

  • 在任何情况下都可以在后台线程上运行它吗?例如:stackoverflow.com/questions/25503629/…
  • 我个人永远不会这样做,我建议你不要这样做。如果删除整个后台线程可以解决您的问题,就是这样。如果不是,请解释为什么不。
  • 好的,谢谢。截至目前,它似乎已修复。非常感谢您的回复。
  • 不幸的是,播放声音 CAN 阻塞了主线程。我们最近发现在一些设备上调用 AVAudioPlayer 可以阻塞调用者线程长达 5 秒。可能是一个意外的系统问题(因为我们在早期的操作系统版本中没有注意到)但您仍然不应该声称播放声音不会阻塞主线程。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多