I'm working on an exercise app that needs to be able to play sounds when the app goes into the background and also when the screen is locked. I also need to allow sounds from other apps to play (such as music) while also allowing my sound effects to come through.
I had this working in iOS 9 by using AVAudioSessionCategoryAmbient, but as soon as my app becomes inactive or the screen locks, the sounds stop.
Here's a simplified version of my code in a demo app:
import UIKit
import AVFoundation
class ViewController: UIViewController {
var session: AVAudioSession = AVAudioSession.sharedInstance()
var timer = Timer()
let countdownSoundFile = "154953__keykrusher__microwave-beep"
let countdownSoundExt = "wav"
var audioPlayer = AVAudioPlayer()
override func viewDidLoad() {
super.viewDidLoad()
activateAudio()
}
func activateAudio() {
_ = try? session.setCategory(AVAudioSessionCategoryAmbient, with: [])
_ = try? session.setActive(true, with: [])
}
@IBAction func play() {
timer = Timer.scheduledTimer(timeInterval: 2.0, target: self, selector: #selector(ViewController.playSound), userInfo: nil, repeats: true)
}
func playSound() {
if let soundURL = Bundle.main.url(forResource: countdownSoundFile, withExtension: countdownSoundExt) {
do {
print("sound playing")
try audioPlayer = AVAudioPlayer(contentsOf: soundURL)
audioPlayer.prepareToPlay()
audioPlayer.play()
} catch {
print("no sound found")
}
}
}
}
I also checked the Audio, Airplay, and Picture in Picture
capability in Background Modes, which added the Required background mode to my plist.
I'm testing this on a device, and as soon as I lock the screen or press the home button, my sounds stop, and they resume once my app becomes active again.
I found a workaround by using:
var mySound: SystemSoundID = 0
AudioServicesCreateSystemSoundID(soundURL as CFURL, &mySound)
AudioServicesPlaySystemSound(mySound);
but this doesn't allow the volume of the sounds to be changed, and I also need to use AVSpeechSynthesizer, and this workaround doesn't work for that.
Any ideas on what I can do to make this work?
EDIT:
I changed the category line to _ = try? session.setCategory(AVAudioSessionCategoryPlayback, with: [.mixWithOthers])
and this allows music to be played while the app is running, however the sounds still stop when the screen locks or goes into the background. I need the sounds to continue to play in these scenarios.
EDIT:
As the answer pointed out, I cannot play sounds when my app is backgrounded, but using _ = try? session.setCategory(AVAudioSessionCategoryPlayback, with: [.mixWithOthers])
does allow sounds to play when the screen turns off and mixes with sounds (music) from other apps.