2

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.

OffensivelyBad
  • 621
  • 8
  • 16

2 Answers2

6

You cannot play in the background with an Ambient audio session category. Your category must be Playback.

To allow sounds from other apps to play, modify your Playback category with the Mixable option (.mixWithOthers).

(Also keep in mind that you can change your category at any time. You could have it be Ambient most of the time but switch to Playback when you know you're about to go into the background so that you can keep playing.)

EDIT Also it occurs to me that there is another possible misconception that might need clearing up. You cannot (easily) start a new sound while in the background. All that background audio allows you to do is continue playing the current sound when your app goes into the background. Once that sound stops (in the background), your app suspends and that's the end of that.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • 3
    and need to enable `Background Modes Capabilities` for Audio too. – iphonic Nov 17 '16 at 11:35
  • @iphonic please read the question. He says he did that. The question is why that's insufficient. – matt Nov 17 '16 at 15:23
  • @matt I edited my question with an update: your suggestion allows music from a different app to play while my app plays sounds, but as soon as the screen turns off or app goes into the background my app sounds stop. Any ideas? – OffensivelyBad Nov 17 '16 at 18:16
  • Let's debug. What happens if you (temporarily) give up your idea of mixability and _don't_ use the Mixable option. You just use Playback, plain and simple. Does your sound continue in the background then? – matt Nov 17 '16 at 18:17
  • Also please see my new edit to my answer, as I'm a bit worried you may have a false idea of what background sound means. – matt Nov 17 '16 at 18:19
  • Thanks for your input. I see that now when the screen locks my sounds continue to play and they can mix with music. Thanks for your input. This helps me out tremendously. – OffensivelyBad Nov 17 '16 at 18:34
  • I'm happy you got it sorted! I wasn't sure quite where the issue was, so I threw a lot of info at you — sorry about that. – matt Nov 17 '16 at 20:20
2

check here this answer in detail. You need to enable Audio Mode as well from the app settings.

do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, with: .mixWithOthers)
print("AVAudioSession Category Playback OK")
do {
    try AVAudioSession.sharedInstance().setActive(true)
    print("AVAudioSession is Active")
} catch {
    print(error)
}
} catch {
print(error)
}
Community
  • 1
  • 1
Muhammad Adil
  • 4,358
  • 3
  • 32
  • 36