Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AVAudioRecorder not recording in background after audio session interruption ended

I am recording audio in my app, both in foreground and in background. I also handle AVAudioSessionInterruptionNotification to stop recording when interruption begins and start again when it ends. Although in foreground it works as expected, when app is recording in background and I receive a call it doesn't start again recording after call ends. My code is the following:

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

Note that fileURL points to new caf file in a NSDocumentDirectory subdirectory. Background mode audio is configured. I also tried voip and play silence, both to no success.

The NSError in AVAudioSessionInterruptionTypeEnded block is a OSStatus error 560557684 which I haven't found how to tackle.

Any help would be much appreciated.

like image 666
ozzotto Avatar asked Mar 13 '15 15:03

ozzotto


2 Answers

Error 560557684 is for AVAudioSessionErrorCodeCannotInterruptOthers. This happens when your background app is trying to activate an audio session that doesn't mix with other audio sessions. Background apps cannot start audio sessions that don't mix with the foreground app's audio session because that would interrupt the audio of the app currently being used by the user.

To fix this make sure to set your session category to one that is mixable, such as AVAudioSessionCategoryPlayback. Also be sure to set the category option AVAudioSessionCategoryOptionMixWithOthers (required) and AVAudioSessionCategoryOptionDuckOthers (optional). For example:

// 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]);
}

The error code 560557684 is actually 4 ascii characters '!int' in a 32 bit integer. The error codes are listed in the AVAudioSession.h file (see also 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 */
...
like image 121
progrmr Avatar answered Sep 17 '22 13:09

progrmr


I added the following

[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];

before configuring AVAudioSession and it worked. Still don't know what bugs may appear.

like image 21
ozzotto Avatar answered Sep 17 '22 13:09

ozzotto