27

I can't get the iOS 7 AVSpeechSynthesizer to work when my iOS app is in background mode. I have added the "App plays audio" key to the app's supported background modes, but I still can't get it to work.

I have also investigated the possibility of creating an AVMutableCompositionTrack, with an AVSpeechSynthesizer utterance, and then somehow play it with a player that would be able to run in the background - but with no luck.

Did anyone have better luck than me in using AVSpeechSynthesizer in the background?

Sam Spencer
  • 8,492
  • 12
  • 76
  • 133
user_lion
  • 383
  • 3
  • 7

4 Answers4

43
  1. You must set "Audio and AirPlay" in background modes.
  2. You have to configure the audio session:
    NSError *error = NULL;
    AVAudioSession *session = [AVAudioSession sharedInstance];
    [session setCategory:AVAudioSessionCategoryPlayback error:&error];
    if(error) {
        // Do some error handling
    }
    [session setActive:YES error:&error];
    if (error) {
        // Do some error handling
    }
Itachi
  • 5,777
  • 2
  • 37
  • 69
imihaly
  • 1,838
  • 13
  • 11
  • Does this actually allow you to play in audio background mode? – Chris Truman Nov 11 '13 at 23:17
  • 1
    @ChrisTruman, I can confirm that it works. imihaly, does the "session setActive" call cause your app to stay running in the background and increase your app's power requirements? I will do some testing, but my guess is that the answer is yes, so you would want to make the calls above, play your synthesized speech, and then set your session's active status back to NO once you were done. – Duncan C Jan 31 '14 at 14:47
  • 1
    @imihaly, I've used your code and it works. (+1) Based on my testing, the app does not appear to stay running in the background. However, the app I'm developing is intended to be run in the background for long periods, and may be suspended repeatedly during it's lifetime. Sometimes speech synthesis stops working for reasons I don't understand. Any ideas? – Duncan C Feb 03 '14 at 15:25
  • I've done this, but my app still stops talking when the screen goes dark from idle. Mmm. – Rob N May 05 '14 at 16:33
  • Worked for me in the 8.3 simulator. – Andrew Duncan Apr 14 '15 at 21:00
  • I can add that AVAudioSessionCategorySoloAmbient works in the Simulator (audio plays in background), but not on the hardware. At least in my situation (triggering audio via handleWatckKitExtensionRequest). Changing category to Playback as suggested above fixed problem. – Andrew Duncan May 15 '15 at 22:48
  • @imihaly where do you put this code? – Shining Love Star Apr 11 '22 at 00:57
9

For swift 3, import AVKit (or AVFoundation) then add

try? AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)

to viewWillAppear(). This allows audio to play regardless of the mute switch status and in the background with the screen off.

*Edit: AVAudioSession is defined in AVFoundation and is also available with AVKit

*Edit 2: Screenshot of auto complete showing that AVAudioSession is available in AVKit

enter image description here

Chris
  • 955
  • 15
  • 20
  • AVKit has to replaced with AVFoundation and set "Audio and AirPlay" in background modes is obviously still needed – cristallo Sep 11 '17 at 10:20
  • AVKit is the higher level framework, AVFoundation is the framework to use for more fine grain control but [AVKit](https://developer.apple.com/documentation/avkit) is in no way replaced by [AVFoundation](https://developer.apple.com/documentation/avfoundation). – Chris Sep 11 '17 at 14:42
  • I an not saying that AVFoundation is an AVKit replacement. I am only saying that the [AVAudioSession](https://developer.apple.com/documentation/avfoundation/avaudiosession) is not included in AVKit but in AVFoundation . So in this context you should include AVFoundation. – cristallo Sep 11 '17 at 15:00
9

This code works for me in Swift 5

    do {
       try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: AVAudioSession.CategoryOptions.mixWithOthers)
       try AVAudioSession.sharedInstance().setActive(true)
    } catch {
        print(error)
    }

    let utterance = AVSpeechUtterance(string: voiceOutdata)


    let synth = AVSpeechSynthesizer()
    synth.speak(utterance)

According to https://forums.developer.apple.com/thread/38917

AVAudioSessionCategoryOptionMixWithOthers is added along with the Playback Category when the session is mixable there are some internal checks as to the "why" an application is awake before it is allowed to play audio.

Juncheng Tang
  • 139
  • 1
  • 7
0

@imihaly has told "You must set "Audio and AirPlay" in background modes." that is understandablelook the picture

You need to enable that from there, Second, in the AVSpeechSynthesizer code section you have to write below code

 let audioSession = AVAudioSession.sharedInstance()
            try! audioSession.setCategory(
                AVAudioSession.Category.playback,
                options: AVAudioSession.CategoryOptions.duckOthers
            )
                 
Ucdemir
  • 2,852
  • 2
  • 26
  • 44