5
votes

If I set my app's audio session mode to AVAudioSessionCategoryPlayback with the options:

AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers |
AVAudioSessionCategoryOptionDuckOthers

Everything works great and my app plays its audio with Apple music ducking in the background.

However, if my app's audio session category is AVAudioSessionCategoryAmbient prior to the change to AVAudioSessionCategoryPlayback, Apple music (and other music apps) stop playing.

Here is my code (I check for errors and return values, but for clarity I removed those parts in the snippet:

// If I comment out this call, my app will duck others... 
// If it is commented in, rather than ducking, my app stops all other audio
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient
                                 withOptions:0
                                       error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];

// Do other stuff in the app and at some point the following code gets called

theOptions = AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers |
                     AVAudioSessionCategoryOptionDuckOthers

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback
                                 withOptions:theOptions
                                       error:nil];

I've tried deactivating the session between changes, but that doesn't make any different nor does activating it every time. The only thing that I can find to allow my app to play audio and duck others is to not set up an ambient session at any point in my app, but I need to play ambient audio at some points in the app so this solution isn't viable. Please help :)

1
Did you solve this? I am having the same issue...talsharonts
Unfortunately not. I just ended up not using an ambient session category. Note, I have not tested this on any of the newer OS versions (>10) to see if the behavior is different.Shackleford

1 Answers

1
votes

(Swift 4 answer) Tested on iOS 11 - you should either use .duckOthers or .mixWithOthers when setting your ambient session

func prepareSessionForPlayback() {
    do {
        try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryAmbient, with: [.duckOthers]) // .duckOthers or .mixWithOthers
        do {
            try AVAudioSession.sharedInstance().setActive(true)
        } catch let error as NSError {
            print (error)
        }
    } catch let error as NSError {
        print (error)
    }
}

func sessionDidFinish() {
    do { try AVAudioSession.sharedInstance().setActive(false) } catch { }
}

Once SessionDidFinish is completed you can set a different option. If you are using TTS, you also need to assure that you are not setting a .postUtteranceDelay on your last utterance before calling sessionDidFinish. Use the AVSpeechSynthesizerDelegate methods to catch when an utterance has really completed.