How do I record audio on iPhone with AVAudioRecorder?
Solution 1
Actually, there are no examples at all. Here is my working code. Recording is triggered by the user pressing a button on the navBar. The recording uses cd quality (44100 samples), stereo (2 channels) linear pcm. Beware: if you want to use a different format, especially an encoded one, make sure you fully understand how to set the AVAudioRecorder settings (read carefully the audio types documentation), otherwise you will never be able to initialize it correctly. One more thing. In the code, I am not showing how to handle metering data, but you can figure it out easily. Finally, note that the AVAudioRecorder method deleteRecording as of this writing crashes your application. This is why I am removing the recorded file through the File Manager. When recording is done, I save the recorded audio as NSData in the currently edited object using KVC.
#define DOCUMENTS_FOLDER [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]
- (void) startRecording{
UIBarButtonItem *stopButton = [[UIBarButtonItem alloc] initWithTitle:@"Stop" style:UIBarButtonItemStyleBordered target:self action:@selector(stopRecording)];
self.navigationItem.rightBarButtonItem = stopButton;
[stopButton release];
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *err = nil;
[audioSession setCategory :AVAudioSessionCategoryPlayAndRecord error:&err];
if(err){
NSLog(@"audioSession: %@ %d %@", [err domain], [err code], [[err userInfo] description]);
return;
}
[audioSession setActive:YES error:&err];
err = nil;
if(err){
NSLog(@"audioSession: %@ %d %@", [err domain], [err code], [[err userInfo] description]);
return;
}
recordSetting = [[NSMutableDictionary alloc] init];
[recordSetting setValue :[NSNumber numberWithInt:kAudioFormatLinearPCM] forKey:AVFormatIDKey];
[recordSetting setValue:[NSNumber numberWithFloat:44100.0] forKey:AVSampleRateKey];
[recordSetting setValue:[NSNumber numberWithInt: 2] forKey:AVNumberOfChannelsKey];
[recordSetting setValue :[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey];
[recordSetting setValue :[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsBigEndianKey];
[recordSetting setValue :[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsFloatKey];
// Create a new dated file
NSDate *now = [NSDate dateWithTimeIntervalSinceNow:0];
NSString *caldate = [now description];
recorderFilePath = [[NSString stringWithFormat:@"%@/%@.caf", DOCUMENTS_FOLDER, caldate] retain];
NSURL *url = [NSURL fileURLWithPath:recorderFilePath];
err = nil;
recorder = [[ AVAudioRecorder alloc] initWithURL:url settings:recordSetting error:&err];
if(!recorder){
NSLog(@"recorder: %@ %d %@", [err domain], [err code], [[err userInfo] description]);
UIAlertView *alert =
[[UIAlertView alloc] initWithTitle: @"Warning"
message: [err localizedDescription]
delegate: nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
return;
}
//prepare to record
[recorder setDelegate:self];
[recorder prepareToRecord];
recorder.meteringEnabled = YES;
BOOL audioHWAvailable = audioSession.inputIsAvailable;
if (! audioHWAvailable) {
UIAlertView *cantRecordAlert =
[[UIAlertView alloc] initWithTitle: @"Warning"
message: @"Audio input hardware not available"
delegate: nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[cantRecordAlert show];
[cantRecordAlert release];
return;
}
// start recording
[recorder recordForDuration:(NSTimeInterval) 10];
}
- (void) stopRecording{
[recorder stop];
NSURL *url = [NSURL fileURLWithPath: recorderFilePath];
NSError *err = nil;
NSData *audioData = [NSData dataWithContentsOfFile:[url path] options: 0 error:&err];
if(!audioData)
NSLog(@"audio data: %@ %d %@", [err domain], [err code], [[err userInfo] description]);
[editedObject setValue:[NSData dataWithContentsOfURL:url] forKey:editedFieldKey];
//[recorder deleteRecording];
NSFileManager *fm = [NSFileManager defaultManager];
err = nil;
[fm removeItemAtPath:[url path] error:&err];
if(err)
NSLog(@"File Manager: %@ %d %@", [err domain], [err code], [[err userInfo] description]);
UIBarButtonItem *startButton = [[UIBarButtonItem alloc] initWithTitle:@"Record" style:UIBarButtonItemStyleBordered target:self action:@selector(startRecording)];
self.navigationItem.rightBarButtonItem = startButton;
[startButton release];
}
- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *) aRecorder successfully:(BOOL)flag
{
NSLog (@"audioRecorderDidFinishRecording:successfully:");
// your actions here
}
Solution 2
Although this is an answered question (and kind of old) i have decided to post my full working code for others that found it hard to find good working (out of the box) playing and recording example - including encoded, pcm, play via speaker, write to file here it is:
AudioPlayerViewController.h:
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
@interface AudioPlayerViewController : UIViewController {
AVAudioPlayer *audioPlayer;
AVAudioRecorder *audioRecorder;
int recordEncoding;
enum
{
ENC_AAC = 1,
ENC_ALAC = 2,
ENC_IMA4 = 3,
ENC_ILBC = 4,
ENC_ULAW = 5,
ENC_PCM = 6,
} encodingTypes;
}
-(IBAction) startRecording;
-(IBAction) stopRecording;
-(IBAction) playRecording;
-(IBAction) stopPlaying;
@end
AudioPlayerViewController.m:
#import "AudioPlayerViewController.h"
@implementation AudioPlayerViewController
- (void)viewDidLoad
{
[super viewDidLoad];
recordEncoding = ENC_AAC;
}
-(IBAction) startRecording
{
NSLog(@"startRecording");
[audioRecorder release];
audioRecorder = nil;
// Init audio with record capability
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryRecord error:nil];
NSMutableDictionary *recordSettings = [[NSMutableDictionary alloc] initWithCapacity:10];
if(recordEncoding == ENC_PCM)
{
[recordSettings setObject:[NSNumber numberWithInt: kAudioFormatLinearPCM] forKey: AVFormatIDKey];
[recordSettings setObject:[NSNumber numberWithFloat:44100.0] forKey: AVSampleRateKey];
[recordSettings setObject:[NSNumber numberWithInt:2] forKey:AVNumberOfChannelsKey];
[recordSettings setObject:[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey];
[recordSettings setObject:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsBigEndianKey];
[recordSettings setObject:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsFloatKey];
}
else
{
NSNumber *formatObject;
switch (recordEncoding) {
case (ENC_AAC):
formatObject = [NSNumber numberWithInt: kAudioFormatMPEG4AAC];
break;
case (ENC_ALAC):
formatObject = [NSNumber numberWithInt: kAudioFormatAppleLossless];
break;
case (ENC_IMA4):
formatObject = [NSNumber numberWithInt: kAudioFormatAppleIMA4];
break;
case (ENC_ILBC):
formatObject = [NSNumber numberWithInt: kAudioFormatiLBC];
break;
case (ENC_ULAW):
formatObject = [NSNumber numberWithInt: kAudioFormatULaw];
break;
default:
formatObject = [NSNumber numberWithInt: kAudioFormatAppleIMA4];
}
[recordSettings setObject:formatObject forKey: AVFormatIDKey];
[recordSettings setObject:[NSNumber numberWithFloat:44100.0] forKey: AVSampleRateKey];
[recordSettings setObject:[NSNumber numberWithInt:2] forKey:AVNumberOfChannelsKey];
[recordSettings setObject:[NSNumber numberWithInt:12800] forKey:AVEncoderBitRateKey];
[recordSettings setObject:[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey];
[recordSettings setObject:[NSNumber numberWithInt: AVAudioQualityHigh] forKey: AVEncoderAudioQualityKey];
}
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/recordTest.caf", [[NSBundle mainBundle] resourcePath]]];
NSError *error = nil;
audioRecorder = [[ AVAudioRecorder alloc] initWithURL:url settings:recordSettings error:&error];
if ([audioRecorder prepareToRecord] == YES){
[audioRecorder record];
}else {
int errorCode = CFSwapInt32HostToBig ([error code]);
NSLog(@"Error: %@ [%4.4s])" , [error localizedDescription], (char*)&errorCode);
}
NSLog(@"recording");
}
-(IBAction) stopRecording
{
NSLog(@"stopRecording");
[audioRecorder stop];
NSLog(@"stopped");
}
-(IBAction) playRecording
{
NSLog(@"playRecording");
// Init audio with playback capability
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/recordTest.caf", [[NSBundle mainBundle] resourcePath]]];
NSError *error;
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
audioPlayer.numberOfLoops = 0;
[audioPlayer play];
NSLog(@"playing");
}
-(IBAction) stopPlaying
{
NSLog(@"stopPlaying");
[audioPlayer stop];
NSLog(@"stopped");
}
- (void)dealloc
{
[audioPlayer release];
[audioRecorder release];
[super dealloc];
}
@end
Hope this will help some of you guys.
Solution 3
I have uploaded a sample project. You can take a look.
Solution 4
Its really helpful. The only problem i had was the size of sound file created after recording. I needed to reduce the file size so i did some changes in settings.
NSMutableDictionary *recordSetting = [[NSMutableDictionary alloc] init];
[recordSetting setValue :[NSNumber numberWithInt:kAudioFormatAppleIMA4] forKey:AVFormatIDKey];
[recordSetting setValue:[NSNumber numberWithFloat:16000.0] forKey:AVSampleRateKey];
[recordSetting setValue:[NSNumber numberWithInt: 1] forKey:AVNumberOfChannelsKey];
File size reduced from 360kb to just 25kb (2 seconds recording).
Solution 5
I've been trying to get this code to work for the last 2 hours and though it showed no error on the simulator, there was one on the device.
Turns out, at least in my case that the error came from directory used (bundle) :
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/recordTest.caf", [[NSBundle mainBundle] resourcePath]]];
It was not writable or something like this... There was no error except the fact that prepareToRecord failed...
I therefore replaced it by :
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *recDir = [paths objectAtIndex:0];
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/recordTest.caf", recDir]]
It now Works like a Charm.
Hope this helps others.
Related videos on Youtube
naitsirch
Updated on March 24, 2022Comments
-
naitsirch about 2 years
Now that iPhone 3.0 SDK is public, I think I can ask this question for those of you that have already been playing with the 3.0 SDK. I want to record audio in my application, but I want to use
AVAudioRecorder
and not the older way of recording like the exampleSpeakHere
shows. There are not any examples of how to best do this in the iPhone Dev Center and only reference to the classes. I am a newbie at iPhone development, so I am looking for a simple sample to get me started. -
naitsirch almost 15 yearsI think I am close to getting your code to work, but I am struggling with the delegate stuff. I am pretty new to Objective C and still have not gotten my head around the proper way to do the delegate for something like this. I have my delegate trying to implement NSObject <AVAudioRecorder>, but I don't think I am doing it right. Would it be too much trouble to post the delegate code also? Thanks.
-
naitsirch almost 15 yearsI just finally got it working by adding this to my delegate class @protocol AVAudioRecorder @optional - (void)audioRecorderBeginInterruption:(AVAudioRecorder *)recorder; - (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag; - (void)audioRecorderEncodeErrorDidOccur:(AVAudioRecorder *)recorder error:(NSError *)error; - (void)audioRecorderEndInterruption:(AVAudioRecorder *)recorder; It seems to work, but I don't know if this is best practice or not. Now I need to persist it to a local data store and play it back among other things.
-
dizy almost 15 yearsThats not right Jim. In your recorder controller header you would do something like... #import <AVFoundation/AVFoundation.h> @interface RecorderViewController : UIViewController <AVAudioRecorderDelegate> {
-
Vaerenberg over 14 yearsThanks. This is probably the only good piece of code on the internet for recording. However using this code gives me a mono playback when I play the recorded file. I have specified the number of channels as 2 in the record settings but don't get a stereo playback. Any ideas?
-
Raptor over 13 yearssome questions: editedObject & editedFieldKey in stopRecording undefined. Can you give me some lights?
-
Admin over 13 yearsHello, When I build and run the second code provided by ShayBC on iphone simulator, I don't get any results but in console it shows that it's working. Does the Iphone simulator use my laptop's speaker and microphone or is it mute and I have to build the app on device?
-
Shaybc about 13 years@Bataly the iphone simulator will play your sound files (mp3 / caf...) and can record through your laptop mic try looking into leopard System Preferences if there are problems, but the best way to test your app is to run it on a real iDevice, and its a good idea for all code you write since there are allot of apps being rejected from the app-store due to crash since they never been tested on a real iDevice, there are more features that are not supported by the simulator (bluetooth, camera, proper multitouch, accelerometer, IAP, GPS, it will have a better performance then the most iDevice...)
-
blakkheartt12 about 13 years[recordSettings setObject:formatObject forKey: AVFormatIDKey]; This line won't let me use AVFormatIDKey as a key. What gives? If I set it to another value it works...
-
Swapnil Luktuke almost 13 yearscan you post the rest of your code as well? cause i think i am missing somethong. I tried changing many settings but am unable to reduce the file size..
-
Ahsan almost 13 years@Shaybc : not working for me..am using the same code, only modified to include the 1st 10 seconds incase of recording.... any suggestions ?
-
saurabh almost 13 yearsu dnt have permission to write in resource folder
-
Avinash over 12 yearsI have uploaded a sample project. You can take a look. github.com/AvinashP/VoiceRecorder
-
Philipp Schlösser over 12 yearsJust in case you don't find the download: Go to 'Downloads' in the upper right corner and then to 'DOWNLOAD PACKAGES'
-
joe kirk over 12 yearsI found that recordEncoding = ENC_AAC; in the viewDidLoad method is the cause of your issue. Try other format, other formats work for me, but not kAudioFormatMPEG4AAC. Not sure why though.
-
joe kirk over 12 yearsLastest findings, for kAudioFormatMPEG4AAC, we cannot set AVEncoderBitRateKey to 12800. Comment off the line and it will work. Will try to find out what should be the correct bit rate for AAC.
-
user523234 over 12 years@Phlibbo: Can't find anything there now?
-
rajt over 12 years@user523234: here is the download url - github.com/AvinashP/VoiceRecorder/downloads#download_128004
-
AJPatel about 12 years@unforgiven hey have idea how to save playing sound in AVAudioPlayer ? not Surrounding || Mic-in sound.
-
William Entriken about 12 yearsIgnore this comment, I am bookmarking your answer. Works great in iOS 5 with minor changes
-
Abhishek about 12 yearswith the help of this code how can i record .amr file format tell me please
-
Olof over 11 yearsHmm. Isn´t there a memory leak at "NSMutableDictionary *recordSettings = [[NSMutableDictionary alloc] initWithCapacity:10];"? recordSettings doesn´t seem to be released anywhere?
-
Dewayne over 11 yearsThe sample code does not compile as noted in the Github issues 6 months ago.
-
Avinash over 11 yearsI have fixed the code and checked in into github. It should work now.
-
Tim Kozak about 11 yearsOPTIMAL SOUND QUALITY SETTINGS I FOUND
-
Prince Kumar Sharma about 11 years@Massimo Cafaro , can we record current playing file in iphone.
-
marxy almost 11 yearsI don't think you can write to the bundle so I write to Documents like this: NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *basePath = paths[0]; NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/recordTest.caf", basePath]];
-
Olie almost 11 yearsI'm curious why you use
now = [NSDate dateWithTimeIntervalSinceNow:0]
, rather than justnow = [NSDate date]
. Are they not functionally the same? -
Massimo Cafaro almost 11 years@Olie, they are functionally the same. I adapted my original code in which I was not using the current date, so I had already in my code a statement like recordingDate = [NSDate dateWithTimeIntervalSinceNow:lastEvent]. I just changed it to the one you saw in the code snippet, but, being lazy, I did not rewrite the statement ;-)
-
Vaibhav Limbani about 10 years@Raptor editedObject is NSMutableDictionary & editedFieldKey is Key for that Dictionary Consider NSMutableDictionary=[editedObject setValue:[NSData dataWithContentsOfURL:url] forKey:@"editedFieldKey"]; Hope this will help you.
-
Husam over 8 yearsThanks bro, this is ur code in Swift :
let recordSettings:[String:AnyObject] = [ AVFormatIDKey:Int(kAudioFormatLinearPCM), AVLinearPCMIsFloatKey:false, AVLinearPCMIsBigEndianKey:0, AVLinearPCMIsNonInterleaved:false, AVSampleRateKey:44100.0, AVNumberOfChannelsKey:2, AVEncoderBitRateKey:12800, AVLinearPCMBitDepthKey:16, AVEncoderAudioQualityKey:AVAudioQuality.Max.rawValue]
-
Yogendra Girase almost 7 years@MassimoCafaro how i audio record when app is background ?. i have tested your code it is not working on background mode.
-
CodeBrew about 6 yearsThis example code has a major mistake of writing audio file to the bundle resource URL. Check the correction provided by @marxy
-
Ashley Mills over 5 yearsDon't use
-[NSUserDefaults synchronize]
. From Apple's documentation "this method is unnecessary and shouldn't be used." -
Debug Arnaut over 3 yearsThanks man! This answer needs to be higher up since recent iOS versions require that privacy info in the info.plist file. Also, FYI to any other iOS newbies who stumble across this: You can open "Info.plist" and then just right-click the background near the bottom of the file, hit "Add row", and paste in "NSMicrophoneUsageDescription"