views:

14759

answers:

9

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 example SpeakHere 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. Thanks in advance.

+28  A: 

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

}

unforgiven
Awesome, I can't wait to code this into my project. Thank you so much for this answer, drove me crazy last night trying to get it to work on my own, but I did learn the class pretty well. :)
Jim Zimmerman
I 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.
Jim Zimmerman
I 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.
Jim Zimmerman
Thats not right Jim. In your recorder controller header you would do something like... #import <AVFoundation/AVFoundation.h>@interface RecorderViewController : UIViewController <AVAudioRecorderDelegate> {
dizy
Thanks, I will try that. I had a feeling I was doing it wrong.
Jim Zimmerman
Thanks. 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?
lostInTransit
Shivan Raptor
A: 

Ok so the answer I got helped me in the right direction and I am very thankful. It helped me figure out how to actually record on the iPhone, but I thought I would also include some helpful code I got from the iPhone Reference Library:

http://developer.apple.com/IPhone/library/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/AudioandVideoTechnologies/AudioandVideoTechnologies.html#//apple_ref/doc/uid/TP40007072-CH19-SW14

I used this code and added it to the avTouch example fairly easily. With the above code sample and the sample from the reference library, I was able to get this to work pretty good.

Jim Zimmerman
A: 

hi unforgiven. that's a great post, thank you for that. i have set up all the code for recording (start and stop) as well as playing (start and stop). But, i am keep getting Linking errors regarding the AV recorder and player objects. the error goes something like that: _AVFormatIDKey, referenced from: _AVFormatIDKey$non_lazy_ptr in FirstViewController.o i have tried to find something regarding this error, but couldn't find anything. please help me, thanks RonB

ronb
You'd get more help posting a new question than burying a question in the answers.
mahboudz
You have to add the AVFoundation.framework in Project->Edit Active Target->General->Linked libraries so the linker can find the libs (and perhaps you also may have to add the AudioToolbox.framework).
olegueret
A: 

hi jim, i wanted to compile the avTouch project from apple's developer site, but got errors in these lines:

  • (void)updateCurrentTime;
  • (void)updateViewForPlayerState; : error: expected `{’ before ‘-’ token
  • (void)updateViewForPlayerInfo; : error: expected `{’ before ‘-’ token

  • (void)setupAudioSession; : error: expected `{’ before ‘-’ token

  • (void)ffwd : error: expected `{’ before ‘-’ token

  • (void)rewind : error: expected `{’ before ‘-’ token

  • (void)awakeFromNib : error: expected `{’ before ‘-’ token

and i did not chance anything inside the code! could you please tell me what is wrong there?

greetings blacksheep

blacksheep
You'd get more help posting a new question than burying a question in the answers.
mahboudz
A: 

hi jim, can you suggest me how i can convert .caf to mp3 file format . iam using AVrecoder class to record the voice ineed that file in mp3 format .

thank you

kumaryr
A: 

source code, please?

Can you use the simulator to test it out>>>>>>>>>>>>>>>>>>>>>>?

qwerty
A: 

In the following link you can find useful info about recording with AVAudioRecording. In this link in the first part "USing Audio" there is an anchor named “Recording with the AVAudioRecorder Class.” that leads you to the example.

http://developer.apple.com/library/ios/#documentation/AudioVideo/Conceptual/MultimediaPG/UsingAudio/UsingAudio.html%23//apple_ref/doc/uid/TP40009767-CH2-SW6

tico
A: 

Hi, 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.

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).

Avinash
A: 

@kuhmaryr I guess you need to change the Format in the Settings to

[recordSetting setValue :[NSNumber numberWithInt:kAudioFormatMPEGLayer3] forKey:AVFormatIDKey];
Erle