iOS Camera: `AVCaptureAudioDataOutput` activate audio session on the fly, avoid background music stutter

Hi!

I have created a Camera using AVFoundation which is able to record video and audio using AVCaptureVideoDataOutput and AVCaptureAudioDataOutput. I create my capture session, attach all inputs and the video- and audio-data outputs, and the Camera then sits idle. The user is now able to start a video recording.

Problem

The problem with this is that immediately after I start the capture session, the background music stutters. This is really annoying, since the Camera is the start-screen in our app and I want to delay the stuttering until the Audio is actually needed, which is when the user starts recording a video.

I know that this is somehow possible because Snapchat works that way - you open the App and background audio smoothly continues to play. Once you start recording, there is a small stutter on the background music, but the Camera smoothly operates and starts recording once the short stutter is over.

My code:

func configureSession() {

    captureSession.beginConfiguration()

    // Video, Photo and Audio Inputs
    ...

    // Video Output
    ...

    // Audio Output
    audioOutput = AVCaptureAudioDataOutput()
    guard captureSession.canAddOutput(audioOutput!) else {
      throw CameraError.parameter(.unsupportedOutput(outputDescriptor: "audio-output"))
    }
    audioOutput!.setSampleBufferDelegate(self, queue: audioQueue)
    captureSession.addOutput(audioOutput!)

    try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playAndRecord,
                                                    options: [.mixWithOthers,
                                                              .allowBluetoothA2DP,
                                                              .defaultToSpeaker,
                                                              .allowAirPlay])

    captureSession.commitConfiguration()
}

What I tried

Delay configuring the AVAudioSession.sharedInstance()

I tried to first configure the AVAudioSession.sharedInstance with the category AVAudioSession.Category.playback, and switch to .playAndRecord once I want to start recording audio.

This didn't work and the AVCaptureSessionRuntimeError event gets invoked with the Error code -10851, which means kAudioUnitErr_InvalidPropertyValue. I think this means that the AVCaptureAudioDataOutput is not allowed to record from the Audio Session, but I don't event want to do that right now - it should just be idle.

Delay adding the AVCaptureAudioDataOutput output

I tried to not add the audio output (AVCaptureAudioDataOutput) in the beginning, and only add it "on-demand" once the user starts recording, and while that worked fine for the background music (no stutter when starting, only short stutter once the user starts recording, exactly how I want it), it made the Preview freeze for a short amount of time (because the Capture Session is being reconfigured via beginConfiguration + audio output adding + commitConfiguration)

Does anyone know how it's possible to achieve what I'm trying to do here - or how Snapchat does it? Any help appreciated, thanks!

Hi mrousavy,

I am not sure if this is a preferred method, however, I have been able to make the desired functionality work using the following.

When you initialise the capture session, ensure captureSession.automaticallyConfiguresApplicationAudioSession = true (this is the default).

In your AppDelegate file

  1. set AVAudioSession.Category to ambient
  2. AVAudioSession.sharedInstance().setActive(true)

On record tap:

  1. AVAudioSession.sharedInstance().setActive(false)
  2. Set your AVAudioSession.Category to playAndRecord
  3. AVAudioSession.sharedInstance().setActive(true)
  4. set captureSession.automaticallyConfiguresApplicationAudioSession = false
  5. add your audio input to the capture session
  6. Begin the video recording.

On stop record tap:

  1. Stop video recording.
  2. AVAudioSession.sharedInstance().setActive(false)
  3. remove your audio input from the capture session
  4. Set your AVAudioSession.Category to ambient
  5. AVAudioSession.sharedInstance().setActive(true)

Again, I'm not sure if this is the best way of doing it, but this is what has worked for me. Hopefully this will help you.

Ben

iOS Camera: `AVCaptureAudioDataOutput` activate audio session on the fly, avoid background music stutter
 
 
Q