I have an app where the user can play voice messages received from other users. Playing the voice messages should interrupt device audio (music, podcast, etc playing from other apps), play the voice messages and then let the device audio continue.
Here is a use specific use case I am trying to achieve
- the user starts playing music on the device via Apple Music
- the user opens the app and taps a voice message
- the Apple Music stops
- voice message in the app plays
- Apple Music continues playing
With setting AVAudioSession
s category to .ambient
I can play the voice message "over" the playing Apple Music, but that is not what I need exactly.
If I use the .playback
category that makes the Apple Music stop, plays the voice message in the app but Apple Music does not continue playing afterwards.
3
Answers
You’ve already discovered that you can interrupt other audio apps by activating a
.playback
category audio session. When you finish playing your audio and want the interrupted audio to continue, deactivate your audio session and pass thenotifyOthersOnDeactivation
option.e.g.
I think those apps that should continue like Apple Music, Spotify, Radio apps etc implement the functionality to handle interruptions and when another app’s audio is deactivated / wants to hand back responsibility of the audio.
So could you try and see if this works
In theory, Apple has provided a "protocol" for interrupting and resuming background audio, and in a downloadable example, I show you what it is and prove that it works:
https://github.com/mattneub/Programming-iOS-Book-Examples/tree/master/bk2ch14p653backgroundPlayerAndInterrupter
In that example, there are two projects, representing two different apps. You run both of them simultaneously. BackgroundPlayer plays sound in the background; Interrupter interrupts it, pausing it, and when it is finished interrupting, BackgroundPlayer resumes.
This, as you will see, is done by having Interrupter change its audio session category from ambient to playback while interrupting, and changing it back when finished, along with first deactivating itself entirely while sending the
.notifyOthersOnDeactivation
signal:The trouble, however, is that response to
.notifyOthersOnDeactivation
is entirely dependent on the other app being well behaved. My other app, BackgroundPlayer, is well behaved. This is what it does:As you can see, we register for interruption notifications, and if we are interrupted, we look for the
.shouldResume
option — which is the result of the interrupter setting thenotifyOthersOnDeactivation
in the first place.So far, so good. But there’s a snag. Some apps are not well behaved in this regard. And the most non-well-behaved is Apple’s own Music app! Thus it is actually impossible to get the Music app to do what you want it to do. You are better off using ducking, where the system just adjusts the relative levels of the two apps for you, allowing the background app (Music) to continue playing but more quietly.