Detecting when other apps play audio on iOS

Apps that play ambient audio, such as games, should not interrupt other apps that play audio in the background. We can accomplish this by setting the appropriate category on the shared AVAudioSession instance:

let audioSession = AVAudioSession.sharedInstance()
try audioSession.setCategory(.ambient, mode: .default)

By setting the category to .ambient, we tell iOS that mixing the audio from your app with other apps is acceptable.

Avoiding clashes

To avoid clashing, apps like games may also want to limit playback to sound effects only and mute their soundtrack while music apps play in the background. We can easily do this by checking the AVAudioSession.secondaryAudioShouldBeSilencedHint property:

let audioSession = AVAudioSession.sharedInstance()
if audioSession.secondaryAudioShouldBeSilencedHint {
    // Mute the game's background music.
} else {
    // Play game's background music!

Detecting changes

You can detect when other apps start and stop playing audio by subscribing to AVAudioSession.silenceSecondaryAudioHintNotification.

    selector: #selector(handleSecondaryAudioHintChange(_:)),
    name: AVAudioSession.silenceSecondaryAudioHintNotification,
    object: nil

// ...

func handleSecondaryAudioHintChange(_ notification: Notification) {
    guard let typeValue = notification.userInfo?[AVAudioSessionSilenceSecondaryAudioHintTypeKey] as? UInt,
          let hintType = AVAudioSession.SilenceSecondaryAudioHintType(rawValue: typeValue) else {

    if hintType == .begin {
        // Other app started playing audio... Mute game's background music.
    } else {
        // Other app stopped playing audio... Resume playing background music.

I recommend creating an “Audio Manager” singleton class to glue everything together. The can be responsible for playing the looping audio files that make the soundtrack, registering itself for secondary audio hint notification changes, and starting or stopping the music accordingly.