【问题标题】:AVAudioRecorder not recording in background after audio session interruption ended音频会话中断结束后,AVAudioRecorder 未在后台录制
【发布时间】:2015-03-13 15:34:52
【问题描述】:

我正在我的应用中录制前台和后台的音频。我还处理 AVAudioSessionInterruptionNotification 以在中断开始时停止录制并在结束时重新开始。尽管在前台它按预期工作,但当应用程序在后台录制并且我接到电话时,它不会在通话结束后再次开始录制。我的代码如下:

        - (void)p_handleAudioSessionInterruptionNotification:(NSNotification *)notification
        {
            NSUInteger interruptionType = [[[notification userInfo] objectForKey:AVAudioSessionInterruptionTypeKey] unsignedIntegerValue];

            if (interruptionType == AVAudioSessionInterruptionTypeBegan) {
                if (self.isRecording && !self.interruptedWhileRecording) {

                    [self.recorder stop];

                    self.interruptedWhileRecording = YES;
                    return;
                }
            }

            if (interruptionType == AVAudioSessionInterruptionTypeEnded) {
                if (self.interruptedWhileRecording) {
                    NSError *error = nil;
                    [[AVAudioSession sharedInstance] setActive:YES error:&error];

                    NSDictionary *settings = @{
                                       AVEncoderAudioQualityKey: @(AVAudioQualityMax),
                                       AVSampleRateKey: @8000,
                                       AVFormatIDKey: @(kAudioFormatLinearPCM),
                                       AVNumberOfChannelsKey: @1,
                                       AVLinearPCMBitDepthKey: @16,
                                       AVLinearPCMIsBigEndianKey: @NO,
                                       AVLinearPCMIsFloatKey: @NO
                                       };

                    _recorder = [[AVAudioRecorder alloc] initWithURL:fileURL settings:settings error:nil];

                    [self.recorder record];

                    self.interruptedWhileRecording = NO;
                    return;
                }
            }
        }

请注意,fileURL 指向 NSDocumentDirectory 子目录中的新 caf 文件。背景模式音频已配置。我也试过 voip 和 play静默,都没有成功。

AVAudioSessionInterruptionTypeEnded 块中的 NSError 是 OSStatus 错误 560557684,我还没有找到解决方法。

任何帮助将不胜感激。

【问题讨论】:

    标签: ios objective-c xcode avaudiorecorder avaudiosession


    【解决方案1】:

    错误 560557684 适用于 AVAudioSessionErrorCodeCannotInterruptOthers。当您的后台应用程序尝试激活不与其他音频会话混合的音频会话时,就会发生这种情况。后台应用无法启动不与前台应用的音频会话混合的音频会话,因为这会中断用户当前正在使用的应用的音频。

    要解决此问题,请确保将会话类别设置为可混合的类别,例如 AVAudioSessionCategoryPlayback。还要确保设置类别选项AVAudioSessionCategoryOptionMixWithOthers(必需)和AVAudioSessionCategoryOptionDuckOthers(可选)。例如:

    // background audio *must* mix with other sessions (or setActive will fail)
    NSError *sessionError = nil;
    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback
                                     withOptions:AVAudioSessionCategoryOptionMixWithOthers | AVAudioSessionCategoryOptionDuckOthers
                                           error:&sessionError];
    if (sessionError) {
        NSLog(@"ERROR: setCategory %@", [sessionError localizedDescription]);
    }
    

    错误代码 560557684 实际上是 32 位整数中的 4 个 ascii 字符 '!int'。错误代码列在 AVAudioSession.h 文件中(另请参阅 AVAudioSession):

        @enum AVAudioSession error codes
        @abstract   These are the error codes returned from the AVAudioSession API.
    ...
        @constant   AVAudioSessionErrorCodeCannotInterruptOthers
            The app's audio session is non-mixable and trying to go active while in the background.
            This is allowed only when the app is the NowPlaying app.
    
    typedef NS_ENUM(NSInteger, AVAudioSessionErrorCode)
    {
    ...
        AVAudioSessionErrorCodeCannotInterruptOthers = '!int', /* 0x21696E74, 560557684 */
    ...
    

    【讨论】:

    • 我是否还需要在功能中启用音频背景模式?
    【解决方案2】:

    我添加了以下内容

    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
    

    在配置 AVAudioSession 之前它起作用了。还不知道会出现什么bug。

    【讨论】:

      【解决方案3】:

      当我的应用程序在后台时尝试使用 AVSpeechSynthesizer().speak() 时,我遇到了同样的错误。 @progmr 的回答为我解决了这个问题,尽管我也不得不打电话给AVAudioSession.sharedInstance().setActive(true)。 为了完整起见,这是我在 Swift 5 中的代码。

      application(_:didFinishLaunchingWithOptions:):

      do {
        try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback,
                                                        options: [.mixWithOthers,
                                                                  .duckOthers])
      
      } catch let error as NSError {
        print("Error setting up AVAudioSession : \(error.localizedDescription)")
      }
      

      然后在我的视图控制器中:

      do {
        try AVAudioSession.sharedInstance().setActive(true)
      } catch let error as NSError {
        print("Error : \(error.localizedDescription)")
      }
      
      let speechUtterance = AVSpeechUtterance(string: "Hello, World")
      let speechSynth = AVSpeechSynthesizer()
      speechSynth.speak(speechUtterance)
      

      注意:当setActive(true) 被调用时,它会降低当时正在播放的任何东西的音量。之后要调高音量,您需要致电setActive(false) - 对我来说,最好的时间是在相应的AVSpeechSynthesizerDelegate 方法中通知我演讲已经结束。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-02-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多