更改 AVAudioSession 后没有来自 AVCaptureSession 的音频

Dan*_*son 4 objective-c avfoundation ios avaudiosession

我正在制作一个支持视频播放和录制的应用程序。除了视频播放期间,我总是希望允许背景音频混合(在播放过程中,背景音频应该静音)。因此,我在更改播放状态时使用以下两种方法。当我的 AVPlayer 开始加载时,我调用MuteBackgroundAudio,当我关闭包含它的视图控制器时,我调用ResumeBackgroundAudio. 这按预期工作,离开播放后音频成功返回。

问题是,在至少执行一次此操作后,每当我使用 录制任何内容时AVCaptureSession,都不会录制任何声音。我的会话配置如下:

AVCaptureDevice *audioDevice = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio] firstObject];
AVCaptureDeviceInput *audioDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:&error];

if (error)
{
    NSLog(@"%@", error);
}

if ([self.session canAddInput:audioDeviceInput])
{
    [self.session addInput:audioDeviceInput];
}

[self.session setAutomaticallyConfiguresApplicationAudioSession:NO];

// ... videoDeviceInput
Run Code Online (Sandbox Code Playgroud)

请注意,我尚未设置usesApplicationAudioSession,因此默认为YES.

void MuteBackgroundAudio(void)
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        if ([[AVAudioSession sharedInstance] isOtherAudioPlaying] && !isMuted)
        {
            isMuted = YES;

            NSError *error = nil;
            [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord
                                             withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker
                                                   error:&error];
            if (error)
            {
                NSLog(@"DEBUG - Set category error %ld, %@", (long)error.code, error.localizedDescription);
            }

            NSError *error2 = nil;
            [[AVAudioSession sharedInstance] setActive:YES
                                           withOptions:0
                                                 error:&error2];
            if (error2)
            {
                NSLog(@"DEBUG - Set active error 2 %ld, %@", (long)error.code, error.localizedDescription);
            }
        }
    });
}

void ResumeBackgroundAudio(void)
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        if (isMuted)
        {
            AVAudioSession *audioSession = [AVAudioSession sharedInstance];

            NSError *deactivationError = nil;
            [audioSession setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:&deactivationError];

            if (deactivationError)
            {
                NSLog(@"DEBUG - Failed at deactivating audio session, retrying...");
                ResumeBackgroundAudio();
                return;
            }

            isMuted = NO;
            NSLog(@"DEBUG - Audio session deactivated");

            NSError *categoryError = nil;
            [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord
                          withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker | AVAudioSessionCategoryOptionMixWithOthers
                                error:&categoryError];

            if (categoryError)
            {
                NSLog(@"DEBUG - Failed at setting category");
                return;
            }

            NSLog(@"DEBUG - Audio session category set to mix with others");

            NSError *activationError = nil;
            [audioSession setActive:YES error:&activationError];

            if (activationError)
            {
                NSLog(@"DEBUG - Failed at activating audio session");
                return;
            }

            NSLog(@"DEBUG - Audio session activated");
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

调试

我注意到 audioSession 在调用ResumeBackgroundAudio. 由于以下评论,我的 AVPlayer 似乎没有及时解除分配或停止AVAudioSession.h

请注意,如果会话在运行或暂停 I/O(例如音频队列、播放器、录音机、转换器、远程 I/O 等)时设置为非活动状态,则此方法将在 iOS 8 上或之后链接的应用程序中引发异常。 .

没有声音被记录的事实让我相信audioSession实际上并没有被激活,但我的日志记录表明它确实被激活(总是在递归的第二次迭代中)。

我从这篇文章中得到了使用递归来解决这个问题的想法。

澄清一下,导致问题的流程如下:

  1. 使用 Spotify 播放打开应用程序
  2. 开始播放应用程序中的任何内容
  3. Spotify 静音,播放开始 ( MuteBackgroundAudio)
  4. 播放结束,Spotify 重新开始播放 ( ResumeBackgroundAudio)
  5. 开始录音
  6. 停止录音,因为没有音频而生气

Pau*_*dan 5

我遇到了与您所描述的完全相同的问题,直到最后一个细节([audioSession setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:&deactivationError];无论如何第一次都失败了)

就我而言,唯一可接受的方法是停止然后启动 AVCaptureSession。我不完全确定,但我认为这与 Whatsapp 处理它的方式完全相同 - 他们的相机与我建议的解决方案完全一样。

在已经运行的会话上删除和添加相同的音频输入似乎也有效,但我的相机卡住了很糟糕 - 与会话开始/停止相比没什么。

递归解决方案很好,但我认为“限制”递归调用(添加短延迟和某种最大重试次数)是一个好主意,以防由于合法原因设置每次都失败。否则您的堆栈将溢出,您的应用程序将崩溃。

如果您或任何人找到了更好的解决方案,我很想知道。