iOS 摄像头:`AVCaptureAudioDataOutput` 即时激活音频会话,避免背景音乐断断续续

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

我使用 AVFoundation 创建了一个相机,它能够使用 AVCaptureVideoDataOutputAVCaptureAudioDataOutput 录制视频和音频。我创建我的捕获会话,附加所有输入以及视频和音频数据输出,然后相机闲置。用户现在可以开始视频录制了。

问题

问题在于,在我开始捕获会话 (captureSession.startRunning()) 后,背景音乐立即断断续续。我认为这是因为一旦捕获会话开始 运行,AVCaptureAudioDataOutput 就会在内部激活 AVAudioSession (AVAudioSession.setActive(...)),我不希望它这样做。我希望它闲置(并且不提供任何音频输出缓冲区),直到我明确激活音频会话(一旦用户开始录制)。

这真的很烦人,因为相机是我们应用程序的开始屏幕,每次用户打开或关闭应用程序时,他的音乐都会断断续续。

我知道这在某种程度上是可能的,因为 Snapchat 就是这样工作的——你打开应用程序,背景音频会继续流畅地播放。开始录制后,背景音乐会有一点卡顿,但卡顿结束后,Camera 会平稳运行并开始录制。

我的代码:

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()
}

我试过的

延迟配置 AVAudioSession.sharedInstance()

我尝试先将 AVAudioSession.sharedInstance 配置为类别 AVAudioSession.Category.playback,然后在我想开始录制音频时切换到 .playAndRecord

这没有用,AVCaptureSessionRuntimeError 事件在启动相机后立即被调用,错误代码为 -10851,这意味着 kAudioUnitErr_InvalidPropertyValue。我认为这意味着 AVCaptureAudioDataOutput 不允许从音频会话中录制,但我现在不想这样做 - 它应该只是闲置。

延迟添加 AVCaptureAudioDataOutput 输出

我尝试在开始时不添加音频输出 (AVCaptureAudioDataOutput),只有在用户开始录制后才“按需”添加它,虽然这对背景音乐来说效果很好(没有开始时口吃,一旦用户开始录制,只有短暂的口吃,正是我想要的),它使预览冻结了很短的时间(因为捕获会话正在通过 beginConfiguration + 音频输出添加 + commitConfiguration)

有谁知道如何实现我在这里尝试做的事情 - 或者 Snapchat 是如何做到的?感谢任何帮助,谢谢!

.mixWithOthers 看起来是避免打扰的正确做法,但默认 AVCaptureSession 将为您配置 AVAudioSession,因此请设置

captureSession.automaticallyConfiguresApplicationAudioSession = false

阻止它替换您的设置。

属性 的文档告诉我们 AVCaptureSession 不仅仅是设置 .playAndRecord 类别,这一事实对于您的用例可能很重要:

the receiver ensures the application's audio session is set to the PlayAndRecord category, and picks an appropriate microphone and polar pattern to match the video camera being used

终于想通了。我只是专门为音频 input/output 创建了一个单独的 AVCaptureSession,我将其与主捕获会话的 masterClock 同步。然后我可以 start/stop 即时进行二次捕获会话(在开始录制前不久)