3

I am trying to play a sound from a background thread using an instance of an AVAudioPlayer in Swift 5. Most of the time, it will be successful. But once in a while the audio player fails to play a sound.

It appears as though calling play() twice, or prepareToPlay() and then play() in a row somehow fixes the problem, but this doesn't seem like a good solution to me, as I am worried that this still doesn't guarantee that it will play successfully.

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

I call the methods in this order:

setUpAudio()
startNewAudio()
setPlay()

I can't figure out the problem—I really want to just call play() once and have everything work fine.

star8163264
  • 148
  • 2
  • 8
  • “play a sound from a background thread using an instance of an AVAudioPlayer in Swift 5.” Why? Just don’t do that and all will be well. – matt May 31 '19 at 23:41
  • Do you mean why am I playing it from a background thread? Being honest, I am not actually sure if it is indeed beneficial to play it from a background thread, but I assumed it is. Does playing it in the background not free up the main thread? – star8163264 May 31 '19 at 23:44
  • 1
    Sound is played asynchronously. Talk to the player only on the main thread. – matt May 31 '19 at 23:53
  • Okay awesome, thanks for the feedback. I have seen some posts on here where play() is called in the background. Any ideas why? And regardless, I am still curious as to why calling play() sometimes doesn't work in this scenario... – star8163264 May 31 '19 at 23:56

1 Answers1

4

There is no reason to say play on a background thread; playing a sound does not block the main thread. Moreover there is no reason to suppose that AVAudioPlayer is thread safe. And YOUR code is certainly not thread safe, as you are talking to the audio player simultaneously from different threads. So you’re using threads incorrectly. There’s no point discussing wrong behavior results. Take away your background thread and try your code doing things the right way. If there is still a problem we can talk about that.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Is it acceptable to run it on a background thread in any instance? For exmple: https://stackoverflow.com/questions/25503629/avaudioplayer-produces-lag-despite-preparetoplay-in-swift – star8163264 Jun 01 '19 at 00:53
  • I personally would never do it, and I'm advising you not to. If removing the whole background thread thing solves your problem, that's that. If not, explain why not. – matt Jun 01 '19 at 01:00
  • Okay, thanks. As of now it appears to be fixed. Your response is much appreciated. – star8163264 Jun 01 '19 at 01:02
  • 3
    Unfortunately, playing the sound CAN block the main thread. We recently discovered on some devices calling play on AVAudioPlayer can block the caller thread up to 5 seconds. Might be an unexpected system issue (as we have not noticed on earlier OS versions) but still you should not claim that playing a sound does not block the main thread. – babibo Dec 13 '21 at 05:05