如何使AVCaptureSession和AVPlayer遵循AVAudioSessionCategoryAmbient?

6
我正在制作一款应用程序,用于录制(AVCaptureSession)和播放(AVPlayerLayer)视频。我希望能够在不暂停其他应用程序的背景音频的情况下实现此操作,并且希望播放尊重静音开关。
在AppDelegate中,我已经设置了AVAudioSessionCategoryAmbient,根据文档,这应该是:
引用:

适用于声音播放非主要的应用程序类别 - 也就是说,您的应用程序可以在关闭声音的情况下成功使用。

该类别也适用于“跟奏”风格的应用程序,例如用户在播放音乐应用程序时弹奏的虚拟钢琴。当您使用此类别时,来自其他应用程序的音频会与您的音频混合。通过屏幕锁定和静音开关(在iPhone上称为铃声/静音开关),您的音频被静音。

这完美地描述了我想要的行为。但它不起作用。
我知道已经设置了AVAudioSessionCategoryAmbient,因为如果我在任何视图控制器中尝试print(AVAudioSession.sharedInstance().category),它会返回AVAudioSessionCategoryAmbient
有什么想法吗?我正在使用Swift,但即使是一个模糊的方向也将不胜感激。
1个回答

14

如何将背景音频与AVCapture会话混合:

如果你有麦克风输入,AVCapture会话会默认将你的应用程序的AVAudioSession设置为AVAudioSessionCategoryPlayAndRecord。你需要告诉它不要这样做:

AVCaptureSession.automaticallyConfiguresApplicationAudioSession = false

然而,这样做只会使应用程序冻结。因为不幸的是,AVAudioSessionCategoryAmbientAVCaptureSession 不兼容。

解决方案是将你的应用程序的 AVAudioSession 设置为带有选项的 AVAudioSessionCategoryPlayAndRecord

do {
    try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord, withOptions: [.MixWithOthers, .AllowBluetooth, .DefaultToSpeaker])
    try AVAudioSession.sharedInstance().setActive(true)

} catch let error as NSError {
    print(error)
}

.MixWithOthers是最重要的选项之一。它允许其他应用程序的音频播放。但它会切换到从听筒输出,这非常奇怪(起初我以为它会被压低)。所以.DefaultToSpeaker将其移动到底部扬声器,.AllowBluetooth允许您保持蓝牙音频通过耳机输出,同时启用蓝牙麦克风。不确定是否可以进一步改进,但它们似乎是所有相关选项。

如何在播放中尊重静音开关:

在录制过程中,您将AVAudioSession设置为AVAudioSessionCategoryPlayAndRecord,但这不尊重静音开关。

因为当存在麦克风输入时,您无法设置AVAudioSessionCategoryAmbient。诀窍是从AVCaptureSession中删除麦克风,然后将AVAudioSession设置为AVAudioSessionCategoryAmbient

do {
    captureSession.removeInput(micInput)
    try AVAudioSession.sharedInstance().setActive(false)
    try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryAmbient)
    try AVAudioSession.sharedInstance().setActive(true)
} catch let error as NSError { print(error) }

一旦您完成了播放并需要返回录制状态,您需要再次设置 AVAudioSessionCategoryPlayAndRecord(并再次使用选项以便后台音频继续播放):

完成回放后需要返回录制状态时,必须重新设置AVAudioSessionCategoryPlayAndRecord(同时再次使用选项以使后台音频继续播放):

返回内容为: <p>完成回放后需要返回录制状态时,必须重新设置<code>AVAudioSessionCategoryPlayAndRecord</code>(同时再次使用选项以使后台音频继续播放):</p>
do {
    try AVAudioSession.sharedInstance().setActive(false)
    try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord, withOptions: [.MixWithOthers, .AllowBluetooth, .DefaultToSpeaker])
    try AVAudioSession.sharedInstance().setActive(true)
} catch let error as NSError { print(error) }

captureSession.automaticallyConfiguresApplicationAudioSession = false
captureSession.addInput(micInput!)

do块中的第一行内容困扰了我很长时间。我不需要将音频会话设置为非活动状态即可切换到AVAudioSessionCategoryAmbient,但当切换回AVAudioSessionCategoryPlayAndRecord时它会暂停后台音频。


简而言之,听起来好像没有办法在麦克风处于活动状态时保持AVAudioSessionCategoryPlayAndRecord模式。 - Warpling
1
纠正上面的评论,当麦克风处于活动状态时,您不能使用“AVAudioSessionCategoryAmbient”模式。 - jnoor
你有没有在5s上遇到任何问题?我们的代码与您在此处发布的非常相似,在6s和4s上可以正确运行,但是当我们在5s上运行时,我们的捕获屏幕会冻结并且无法正常工作。这个问题仅会在我们的某些屏幕之一上使用avplayer后转到捕捉屏幕时才会发生。 - Alex Yurkowski
2
当我使用这段代码时,它会冻结AVCaptureSession大约1-2秒钟。有什么解决方法吗? - Joe Ginley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接