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 :)
(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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With