From 79826c87af06807a29c67bbe6b831ca424301a8c Mon Sep 17 00:00:00 2001 From: Julio Xavier Date: Sat, 15 Jun 2019 14:53:21 -0300 Subject: [PATCH 1/2] handle interruptions on iOS --- ios/AudioRecorderManager.m | 79 ++++++++++++++++++++++++++++---------- 1 file changed, 59 insertions(+), 20 deletions(-) diff --git a/ios/AudioRecorderManager.m b/ios/AudioRecorderManager.m index c500cd37..0ec84790 100644 --- a/ios/AudioRecorderManager.m +++ b/ios/AudioRecorderManager.m @@ -15,6 +15,8 @@ NSString *const AudioRecorderEventProgress = @"recordingProgress"; NSString *const AudioRecorderEventFinished = @"recordingFinished"; +NSString *const AudioRecorderEventInterruptionBegin = @"recordingInterruptionBegin"; +NSString *const AudioRecorderEventInterruptionEnd = @"recordingInterruptionEnd"; @implementation AudioRecorderManager { @@ -33,16 +35,13 @@ @implementation AudioRecorderManager { BOOL _meteringEnabled; BOOL _measurementMode; BOOL _includeBase64; + BOOL _resumeOnInterruptionEnd; } @synthesize bridge = _bridge; RCT_EXPORT_MODULE(); -+ (BOOL)requiresMainQueueSetup { - return YES; -} - - (void)sendProgressUpdate { if (_audioRecorder && _audioRecorder.isRecording) { _currentTime = _audioRecorder.currentTime; @@ -125,24 +124,54 @@ - (NSString *) applicationDocumentsDirectory return basePath; } -RCT_EXPORT_METHOD(prepareRecordingAtPath:(NSString *)path sampleRate:(float)sampleRate channels:(nonnull NSNumber *)channels quality:(NSString *)quality encoding:(NSString *)encoding meteringEnabled:(BOOL)meteringEnabled measurementMode:(BOOL)measurementMode includeBase64:(BOOL)includeBase64) +-(void)audioSessionInterruptionNotification:(NSNotification*)notification { + + // Check the type of notification + if ([notification.name isEqualToString:AVAudioSessionInterruptionNotification]) { + // Check to see if it was a begin interruption + if ([[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] isEqualToNumber:[NSNumber numberWithInt:AVAudioSessionInterruptionTypeBegan]]) { + // dispatch event over the bridge + [self.bridge.eventDispatcher sendAppEventWithName:AudioRecorderEventInterruptionBegin body:@{}]; + + if (_resumeOnInterruptionEnd) { + [self pauseRecording]; + } else { + // stop recording + // this makes possible to prepare and start recording a new session after interruption ends + + _audioRecorder.delegate = nil; // so that audioRecorderDidFinishRecording may not get called on stopRecording + [self stopRecording]; + NSError *error; + + // inactivate session + [_recordSession setActive:NO error:&error]; + + if (error) { + NSLog(@"%@", error); + } + } + + } else if([[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] isEqualToNumber:[NSNumber numberWithInt:AVAudioSessionInterruptionTypeEnded]]){ + // dispatch event over the bridge + [self.bridge.eventDispatcher sendAppEventWithName:AudioRecorderEventInterruptionEnd body:@{}]; + + if (_resumeOnInterruptionEnd) { + [self resumeRecording]; + } + } + } +} + +RCT_EXPORT_METHOD(prepareRecordingAtPath:(NSString *)path sampleRate:(float)sampleRate channels:(nonnull NSNumber *)channels quality:(NSString *)quality encoding:(NSString *)encoding meteringEnabled:(BOOL)meteringEnabled measurementMode:(BOOL)measurementMode includeBase64:(BOOL)includeBase64 resumeOnInterruptionEnd:(BOOL)resumeOnInterruptionEnd) { + // Allow to execute actions when the app is not in foreground + [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; + _prevProgressUpdateTime = nil; [self stopProgressTimer]; - - NSString *filePathAndDirectory = [path stringByDeletingLastPathComponent]; - NSError *error=nil; - //create parent dirs if necessary - if (![[NSFileManager defaultManager] createDirectoryAtPath:filePathAndDirectory - withIntermediateDirectories:YES - attributes:nil - error:&error]) - { - NSLog(@"Create directory error: %@", error); - } - + _audioFileURL = [NSURL fileURLWithPath:path]; - + // Default options _audioQuality = [NSNumber numberWithInt:AVAudioQualityHigh]; _audioEncoding = [NSNumber numberWithInt:kAudioFormatAppleIMA4]; @@ -150,6 +179,7 @@ - (NSString *) applicationDocumentsDirectory _audioSampleRate = [NSNumber numberWithFloat:44100.0]; _meteringEnabled = NO; _includeBase64 = NO; + _resumeOnInterruptionEnd = NO; // Set audio quality from options if (quality != nil) { @@ -223,8 +253,17 @@ - (NSString *) applicationDocumentsDirectory _includeBase64 = includeBase64; } + if (resumeOnInterruptionEnd != NO) { + _resumeOnInterruptionEnd = resumeOnInterruptionEnd; + } + + NSError *error = nil; _recordSession = [AVAudioSession sharedInstance]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(audioSessionInterruptionNotification:) + name:AVAudioSessionInterruptionNotification + object:_recordSession]; if (_measurementMode) { [_recordSession setCategory:AVAudioSessionCategoryRecord error:nil]; @@ -244,8 +283,8 @@ - (NSString *) applicationDocumentsDirectory if (error) { NSLog(@"error: %@", [error localizedDescription]); // TODO: dispatch error over the bridge - } else { - [_audioRecorder prepareToRecord]; + } else { + BOOL prepared = [_audioRecorder prepareToRecord]; } } From 00fa35526bfec4711b29f0b2375c43f3e503adf1 Mon Sep 17 00:00:00 2001 From: Julio Xavier Date: Sat, 15 Jun 2019 14:56:39 -0300 Subject: [PATCH 2/2] resume after interruption iOS by default to match android behavior --- ios/AudioRecorderManager.m | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/ios/AudioRecorderManager.m b/ios/AudioRecorderManager.m index 0ec84790..7e7f3398 100644 --- a/ios/AudioRecorderManager.m +++ b/ios/AudioRecorderManager.m @@ -135,10 +135,7 @@ -(void)audioSessionInterruptionNotification:(NSNotification*)notification { if (_resumeOnInterruptionEnd) { [self pauseRecording]; - } else { - // stop recording - // this makes possible to prepare and start recording a new session after interruption ends - + } else { // stop recording _audioRecorder.delegate = nil; // so that audioRecorderDidFinishRecording may not get called on stopRecording [self stopRecording]; NSError *error; @@ -179,7 +176,7 @@ -(void)audioSessionInterruptionNotification:(NSNotification*)notification { _audioSampleRate = [NSNumber numberWithFloat:44100.0]; _meteringEnabled = NO; _includeBase64 = NO; - _resumeOnInterruptionEnd = NO; + _resumeOnInterruptionEnd = YES; // Set audio quality from options if (quality != nil) { @@ -253,7 +250,7 @@ -(void)audioSessionInterruptionNotification:(NSNotification*)notification { _includeBase64 = includeBase64; } - if (resumeOnInterruptionEnd != NO) { + if (resumeOnInterruptionEnd != nil && resumeOnInterruptionEnd != YES) { _resumeOnInterruptionEnd = resumeOnInterruptionEnd; }