AVAudioRecorder is also built on top of Audio Queue Services. It provides capability to:

  • Record until user stop the recording
  • Record for a specified duration
  • Pause and resume recording
  • Audio-level metering

For recording and playback, we should choose AVAudioSessionCategoryPlayAndRecord for AVAudioSession category.
In order to use the microphone on our device, we need add microphone usage key to application.plist file.

1
2
<key>NSMicrophoneUsageDescription</key>
<string>Need to use the microphone to record</string>

Create AVAudioRecorder

To create an AVAudioRecorder, we need a url to specify a location to record to, a dictionary of settings for the recording session and output error.

1
- (instancetype)initWithURL:(NSURL *)url settings:(NSDictionary<NSString *,id> *)settings error:(NSError * _Nullable *)outError;

Configure recording session

We can configure several different things for our recording session. The general settings are audio data format, sampling rate and number of channels.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
NSMutableDictionary *setting = [NSMutableDictionary dictionary];
/* set format
** Note: the audio format we specify must be compatible with the tpye defined in the url argument. For example,
** .wav pairs to kAudioFormatLinearPCM
** .aac .m4a pair to kAudioFormatMPEG4AAC
** .alac pairs to kAudioFormatAppleLossless
*/
[setting setValue:@(kAudioFormatMPEG4AAC) forKey:AVFormatIDKey];
/* set sampling rate
** Standard sampling rate for audio: 8kHz, 16kHz, 22.05kHz, 44.1kHz
*/
[setting setValue:@(16000.0) forKey:AVSampleRateKey];
/* set channal
** 1 is for single channel, 2 is for stereo
*/
[setting setValue:@(1) forKey:AVNumberOfChannelsKey];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// example for creating a AVAudioRecorder
// create store url
NSString *urlString = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSDate *now = [NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyyMMddHHmmssSSS"];
urlString = [urlString stringByAppendingFormat:@"%@-MySound.acc", [dateFormatter stringFromDate:now]];
NSURL *url = [NSURL fileURLWithPath:urlString];

// set audio recording setting
NSMutableDictionary *setting = @{
AVFormatIDKey: @(kAudioFormatMPEG4AAC),
AVSampleRateKey: @(16000.0),
AVNumberOfChannelsKey: @(1)
}

NSError *error;

AVAudioRecorder *recorder = [[AVAudioRecorder alloc] initWithURL:url settings:setting error:&error];

if (recorder) {
// configure recorder
} else {
// output the error
}

Controlling Recording

1
2
3
4
5
6
7
8
9
10
11
12
13
/* when we call this method, the program creates an audio file at the location specified by the url we created */
- (BOOL)prepareToRecord;

/* all record methods will implicitly call prepareToRecord() */
- (BOOL)record;
- (BOOL)recordAtTime:(NSTimeInterval)time;
- (BOOL)recordForDuration:(NSTimeInterval) duration;
- (BOOL)recordAtTime:(NSTimeInterval)time forDuration:(NSTimeInterval) duration;

- (void)pause;
- (void)stop;
/* This method can't be called before the audio recorder stoped */
- (BOOL)deleteRecording;

Audio Level Metering

Like AVAudioPlayer, the metering is not enabled by default.

1
2
3
4
5
@property(getter=isMeteringEnabled) BOOL meteringEnabled;
- (void)updateMeters;

- (float)peakPowerForChannel:(NSUInteger)channelNumber;
- (float)averagePowerForChannel:(NSUInteger)channelNumber;

Handle Interruption

Pause the recording by your audio session got interrupted.

1
2
3
4
5
6
7
8
9
10
11
12
[[NSNotificationCenter defaultCenter] addObserver:self 
selector:@selector(handleInterruption:)
name:AVAudioSessionInterruptionNotification
object:nil];

- (void)handleInterruption:(NSNotification *)notification {
AVAudioSessionInterruptionType type = [notification.userInfo[AVAudioSessionInterruptionTypeKey] unsignedIntegerValue];

if (type == AVAudioSessionInterruptionTypeBegan) {
[self.recorder pause];
}
}

Audio file Saving and deleting

AVAudioRecorder needs a place to store the recording audio file. It is a good practice that store the audio file in the temporary directory in iOS file system during recording, and then copy the file to documents directory for permanent saving.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/* Create temperary url */
NSString *tmpPath = NSTemporaryDirectory();
tmpPath = [tmpPath stringByAppendingPathComponent:@"record.caf"];
NSURL *tmpURL = [NSURL fileURLWithPath:tmpPath];
// ...

/* When saving the audio */
// create destination url for audio file
// use timestamp to be the unique id
NSTimeInterval timestamp = [NSDate timeIntervalSinceRefernceDate];
NSString *fileName = [NSString stringWithFormat:@"%@-%f.caf", audioName, timestamp];

// get documents directory path
NSStirng *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *destPath = [docPath stringByAppendingPathComponent:fileName];
NSURL destURL = [NSURL fileURLWithPath:destPath];

// use NSFileManager to copy the file
NSError *error;
if (![[NSFileManager defaultManager] copyItemAtURL:tmpURL toURL:destURL error:&error]){
NSLog(@"%@", [error localizedDescription]);
}

/* delete audio file */
NSError *error;
BOOL success = [[NSFileManager defaultManager] removeItemAtURL:audioFileURL error:&error];
if (!success) {
NSLog(@"Unable to delete: %@", [error localizedDescription]);
}

Test app is Here.

AVFoundation Developer Guide