Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Switching from AVAudioSession Ambient mode to Playback mode is stopping other apps' audio

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 :)

like image 595
Shackleford Avatar asked Nov 08 '22 20:11

Shackleford


1 Answers

(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.

like image 60
Zyntx Avatar answered Nov 15 '22 04:11

Zyntx