Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AVAudioSession switching between mixed and non-mixed modes

I have an app that can show video and I would like the following behavior.

  • When a video first appears onscreen and starts playing, it's audio should mix with audio from other apps that may already be playing. For example, if the user is listening to Spotify, they should hear audio from both Spotify and the playing video.

  • If the user taps a specific button, audio from other apps should be muted so that only audio from the video plays.

  • If the user taps the button again, audio from other apps should resume and the video's audio along with the audio from other apps should mix again.

Essentially, I want to be able to toggle my app's audio mode between "mixing" and "non-mixing".

Here's some code that show's how I'm modifying the AVAudioSession to try to get this functionality.

Turning on Mixing Mode

AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryAmbient
         withOptions:AVAudioSessionCategoryOptionMixWithOthers
               error:nil];
[session setActive:YES withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];

Turning off Mixing Mode

AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayback
         withOptions:0
               error:nil];
[session setActive:YES withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];

The problem that I'm having is that turning on audio mixing after previously turning it off, doesn't notify other apps that they can resume playing audio again. I really, really want that behavior. Is that something that's just not possible.

It seems like the only way to notify other apps that they can resume is to set my app's audio session to be "inactive". Unfortunately doing this while a video is playing causes a warning to be printed out in the console saying that I should stop playing audio before deactivating the audio session. This also has the effect of basically breaking the AVPlayer, as it can no longer play any audio.

Anyone know how to work around these problems? Any solution would be welcome, even ones that are pretty complicated or that make use of a private API.

like image 868
Antonio Avatar asked Oct 28 '15 08:10

Antonio


2 Answers

So as other answers have pointed out you can "pause" the audio of another app. However, you can turn it down by using the .duckWithOthers. Once your audio is finished you can reset that option back to .mixWithOthers and notify other apps that they volume can be restored to the full level.

Let's assume your audio starts when your ViewController appears and stops when your ViewController disappears. Then you can use the following code:

override func viewWillAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    // Use duckOthers so the audio in your VC is slightly louder than the background audio such as Spotify
    updateAVAudioSessionOptions(to: .duckOthers)
  }

  override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    // Reset to mixWithOthers since we are no longer playing audio
    updateAVAudioSessionOptions(to: .mixWithOthers)

    // probably a good idea to stop the audio as well
    player.pause() 
  }

  private func updateAVAudioSessionOptions(to options: AVAudioSession.CategoryOptions) {
    do {
      try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, mode: AVAudioSession.Mode.default, options: options)

      if options == .mixWithOthers {
        // Notify other apps that they volume can be restored to the full level
        try AVAudioSession.sharedInstance().setActive(false, options: .notifyOthersOnDeactivation)
      }

    } catch let error {
      print("Error: \(error)")
    }
  }
like image 58
DoesData Avatar answered Nov 02 '22 06:11

DoesData


I think you're out of luck. Even AVAudioSessionCategoryOptionDuckOthers, which sounds like it should fit your use case, requires you to deactivate your session to return other apps' volume to normal, but as you've seen this causes errors.

like image 36
Rhythmic Fistman Avatar answered Nov 02 '22 07:11

Rhythmic Fistman