I am playing video using this code.
player= [[ MPMoviePlayerViewController alloc] initWithContentURL:movieURL];
player.navigationController.navigationBar.hidden = YES;
player.moviePlayer.scalingMode = MPMovieScalingModeAspectFit;
player.moviePlayer.controlStyle = MPMovieControlStyleNone;
player.moviePlayer.movieSourceType = MPMovieSourceTypeFile;
player.moviePlayer.fullscreen = NO;
[self presentModalViewController:player animated:NO];
Video playing works perfectly But the problem is that after finishing play i am getting this result in console.
[MPAVController] Autoplay: Likely to keep up or full buffer: 0
[MPAVController] Autoplay: Skipping autoplay, not enough buffered to keep up.
and then after i am trying to record the voice but unable to record.
can anybody help me to solve this issue.
same kind of task is done by me... you can take refernce of my code... i hope it helps...
- (IBAction) startRecording:(id)sender
{
NSLog(#"**************Recording start**************");
NSMutableDictionary *recordSetting = [[NSMutableDictionary alloc] init];
// We can use kAudioFormatAppleIMA4 (4:1 compression) or kAudioFormatLinearPCM for nocompression
[recordSetting setValue :[NSNumber numberWithInt:kAudioFormatLinearPCM] forKey:AVFormatIDKey];
// We can use 44100, 32000, 24000, 16000 or 12000 depending on sound quality
[recordSetting setValue:[NSNumber numberWithFloat:41000.0] forKey:AVSampleRateKey];
[recordSetting setValue:[NSNumber numberWithInt: kAudioFormatAppleLossless] forKey:AVFormatIDKey];
// We can use 2(if using additional h/w) or 1 (iPhone only has one microphone)
[recordSetting setValue:[NSNumber numberWithInt: 1] forKey:AVNumberOfChannelsKey];
[recordSetting setValue:[NSNumber numberWithInt:16] forKey:AVEncoderBitRateKey];
NSError *error;
if (![[NSFileManager defaultManager] fileExistsAtPath:mediaPath])
{
[[NSFileManager defaultManager] createDirectoryAtPath:mediaPath withIntermediateDirectories:NO attributes:nil error:&error];
}
mediaPath = [[NSString stringWithFormat:#"%#/sound.caf", DOCUMENTS_FOLDER] retain];
NSURL *url = [NSURL fileURLWithPath:mediaPath];
NSLog(#"AUDIOPATH%#",mediaPath);
err = nil;
NSData *audioData = [NSData dataWithContentsOfFile:[url path] options: 0 error:&err];
if(audioData) {
NSFileManager *fm = [NSFileManager defaultManager];
[fm removeItemAtPath:[url path] error:&err];
}
err = nil;
audioRecorder = [[ AVAudioRecorder alloc] initWithURL:url settings:recordSetting error:&err];
if(!audioRecorder){
NSLog(#"audioRecorder : %# %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];
return;
}
//prepare to record
[audioRecorder setDelegate:self];
[audioRecorder prepareToRecord];
audioRecorder.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
[audioRecorder record];
}
I am not sure if this will help but you should be presenting your MPMoviePlayerViewController with presentMoviePlayerViewControllerAnimated:, not presentModalViewController:animated:, like so:
[self presentMoviePlayerViewControllerAnimated:player];
If you are manually dismissing the MPMoviePlayerViewController you should use dismissMoviePlayerViewControllerAnimated.
Here is a thread that might help solve the issue with the MPAVController logs. It seems like you are doing a lot of customization of the MPMoviePlayerViewController moviePlayer -- you might honestly consider just using an MPMoviePlayerController instead of an MPMoviePlayerViewController.
Without seeing the code you are using to perform voice recording it is impossible to tell whether your voice recording problems are stemming from something to do with MPMoviePlayerViewController or if you have an error elsewhere. I would suggest posting more of your code.
I also found that these messages can be caused by sending an incorrect URL to the media player. Sometimes it really is that simple.
You need to record audio after playing video,so you have to use this notification to know that movie player has completed playing video...For this u need to use this code.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlaybackComplete:)
name:MPMoviePlayerPlaybackDidFinishNotification object:moviePlayerController];
In that moviePlaybackComplete: method you have record audio.
For this purpose you better to use AVAudioPlayer class.
Now use this piece of code for recording..
AVAudioRecorder *recorder = [[AVAudioRecorder alloc] initWithURL:recordedTmpFile settings:recordSetting error:&error];
[recorder setDelegate:self];
[recorder prepareToRecord];
[recorder record];
Check the useApplicationAudioSession property on MPMoviePlayerController. In iOS 3.1.x, the movie player was always getting its own system provided audio session. In newer version of iOS , it can now share the application session, and that's the default value as well. Try switching that property to NO before starting to play your movie.
Related
Hi I need to develop an app that can record, play, stop and overwrite audio. I have done the Recording by using AvAudioRecorder:
NSDictionary *audioSettings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithFloat: 44100],AVSampleRateKey,
[NSNumber numberWithInt: kAudioFormatLinearPCM],AVFormatIDKey,
[NSNumber numberWithInt: 2],AVNumberOfChannelsKey,
[NSNumber numberWithInt: AVAudioQualityLow], AVEncoderAudioQualityKey,
nil];
self.audioRecorder = [[AVAudioRecorder alloc]
initWithURL:audioFileURL
settings:audioSettings
error:nil];
[sliderTimer invalidate];
[self.audioRecorder record];
sliderTimer = [NSTimer scheduledTimerWithTimeInterval:0.2
target:self
selector:#selector(updateSlider)
userInfo:nil repeats:YES];
...and playback is done using AVplayer.
But I dont know how to overwrite the recording. This the outline of my overwrite implementation:
Stop Recording
Move the slider position to the particular point
Then, start recording.
This is the functionality to overwrite the previous recordings.
So, As per the steps I have written
[self.audioRecorder stop];
[[self audioSlider] setValue:self.audioSlider.value animated:YES];
[self.audioRecorder recordAtTime:self.audioSlider.value forDuration:self.audioSlider.maximumValue];
...but its not working. Instead, they totally re-record the file. Could any body help me for this critical situation.
Create audioSession object,its upto you whether you want to activate or deactivate your app’s audio session.(AVAudioSession)
audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory :AVAudioSessionCategoryPlayAndRecord error:&err];
if(err) {
NSLog(#"audioSession: %# %d %#", [err domain], [err code], [[err userInfo] description]);
return;
}
[audioSession setActive:YES error:&err];
Start recording proces,
-startRecording
{
[recordSetting setValue :[NSNumber numberWithInt:kAudioFormatAppleIMA4] forKey:AVFormatIDKey];
// We can use 44100, 32000, 24000, 16000 or 12000 depending on sound quality
[recordSetting setValue:[NSNumber numberWithFloat:32000.0] forKey:AVSampleRateKey];
// We can use 2(if using additional h/w) or 1 (iPhone only has one microphone)
[recordSetting setValue:[NSNumber numberWithInt: 1] forKey:AVNumberOfChannelsKey];
mediaPath = [[NSString stringWithFormat:#"%#/myVoice.mp3", DOCUMENTS_FOLDER] retain];//where you want to save your recorded audio.
NSURL *url = [NSURL fileURLWithPath:mediaPath];
err = nil;
NSData *audioData = [NSData dataWithContentsOfFile:[url path] options: 0 error:&err];
recorder = [[ AVAudioRecorder alloc] initWithURL:url settings:recordSetting error:&err];
[recorder setDelegate:self];
[recorder prepareToRecord];
recorder.meteringEnabled = YES;
BOOL audioHWAvailable = audioSession.inputAvailable;
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;
}
[recorder record];
}
Pause recording:
-pauseRecording
{
[recorder pause];
//[recorder updateMeters];
}
Again resume the process..audiosession will do it for you...
-resumerecording
{
[recorder record];
//[recorder updateMeters];
}
EDIT: [recorder updateMeters]; should be called periodically which refreshes the average and peak power values for all channels of an audio recorder.
You can use timer for that.
For example:
NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(updateAudioDisplay) userInfo:NULL repeats:YES];
-(void)updateAudioDisplay
{
if (!recorder.isRecording)
{
[recorder updateMeters];
}
else
{
if (recorder == nil) {
//recording is not yet started
}
else
{
//paused
}
}
}
You can download the sample code from here.
Good day, can you help me with my project in making a recording project, which is after you recorded it using AVAudioRecorder it will automatically play in a certain time can you give me or site me a link regarding with my question..i am badly needed your help masters, because i'm new at iOS development. thanks in advance guys. have a good day.
here's my code # startrecording:
-(void)startRecording:(UIButton *)sender
{ //for recording
recStopBtn.enabled=NO;
recStopBtn.hidden = NO;
recStopBtn.enabled =YES;
playRecBtn.enabled = NO;
loading.hidden = NO;
[loading startAnimating];
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];
// We can use kAudioFormatAppleIMA4 (4:1 compression) or kAudioFormatLinearPCM for nocompression
[recordSetting setValue :[NSNumber numberWithInt:kAudioFormatAppleIMA4] forKey:AVFormatIDKey];
// We can use 44100, 32000, 24000, 16000 or 12000 depending on sound quality
[recordSetting setValue:[NSNumber numberWithFloat:16000.0] forKey:AVSampleRateKey];
// We can use 2(if using additional h/w) or 1 (iPhone only has one microphone)
[recordSetting setValue:[NSNumber numberWithInt: 1] forKey:AVNumberOfChannelsKey];
// These settings are used if we are using kAudioFormatLinearPCM format
//[recordSetting setValue :[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey];
//[recordSetting setValue :[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsBigEndianKey];
//[recordSetting setValue :[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsFloatKey];
recorderFilePath = [NSString stringWithFormat:#"%#/MySound.caf", DOCUMENTS_FOLDER];
NSLog(#"recorderFilePath: %#",recorderFilePath);
NSURL *url = [NSURL fileURLWithPath:recorderFilePath];
err = nil;
NSData *audioData = [NSData dataWithContentsOfFile:[url path] options: 0 error:&err];
if(audioData)
{
NSFileManager *fm = [NSFileManager defaultManager];
[fm removeItemAtPath:[url path] error:&err];
}
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];
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];
return;
}
// start recording
[recorder record];
lblStatusMsg.text = #"Recording...";
NSLog(#"RECORDING");
//recIcon.image = [UIImage imageNamed:#"rec_icon.png"];
//progressView.progress = 0.0;
//timer = [NSTimer scheduledTimerWithTimeInterval:6.0 target:self selector:#selector(handleTimer) userInfo:nil repeats:YES];
}
If all you need is how to make something happen after a certain amount of time, use an NSTimer. I see you already have one commented out in your code.
To record for a certain amount of time use recordForDuration. To stop recording manually use stop. To play a recording use the url property of the AVAudioRecorder in AVAudioPlayer method initWithContentsOfURL.
So basically, uncomment your NSTimer and then do
AVAudioPlayer *player;
- (void) handleTimer
{
player = [[AVAudioPlayer alloc] initWithContentsOfURL:nameOfAudioRecorder.url];
}
I am making an App in which i have to play music from iPod Music Library using MPMediaPickerController.After playing a song i want to record the song with some external Voice(For example:- User's Voice).I m trying to do the same but getting a problem i.e.when App launches firstly,i choose a song from iPod Music library after that i click on start Recording Button.when i click on Start Recording button my song which i played before stops but the recording is working properly.Recording of User's Voice is working fine but song is not getting recorded as i told that song stops when "Start Recording" button clicked.I am using AVAudioRecorder for Recording.This is my code which i m using.
-(Void)ViewDidLoad
{
self.musicPlayer = [MPMusicPlayerController iPodMusicPlayer];
}
- (void)playOrPauseMusic:(id)sender {
MPMusicPlaybackState playbackState = self.musicPlayer.playbackState;
if (playbackState == MPMusicPlaybackStateStopped || playbackState == MPMusicPlaybackStatePaused) {
[self.musicPlayer play];
} else if (playbackState == MPMusicPlaybackStatePlaying) {
[self.musicPlayer pause];
}
}
- (void)openMediaPicker:(id)sender {
MPMediaPickerController *mediaPicker = [[MPMediaPickerController alloc] initWithMediaTypes:MPMediaTypeMusic];
mediaPicker.delegate = self;
mediaPicker.allowsPickingMultipleItems = NO; // this is the default
[mediaPicker shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationLandscapeRight];
[self presentModalViewController:mediaPicker animated:YES];
}
- (void) startRecording
{
[self.musicPlayer play];
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];
// We can use kAudioFormatAppleIMA4 (4:1 compression) or kAudioFormatLinearPCM for nocompression
[recordSetting setValue :[NSNumber numberWithInt:kAudioFormatAppleIMA4] forKey:AVFormatIDKey];
// We can use 44100, 32000, 24000, 16000 or 12000 depending on sound quality
[recordSetting setValue:[NSNumber numberWithFloat:44100.0] forKey:AVSampleRateKey];
// We can use 2(if using additional h/w) or 1 (iPhone only has one microphone)
[recordSetting setValue:[NSNumber numberWithInt: 1] forKey:AVNumberOfChannelsKey];
[recordSetting setObject:[NSNumber numberWithInt:12800] forKey:AVEncoderBitRateKey];
[recordSetting setObject:[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey];
[recordSetting setObject:[NSNumber numberWithInt: AVAudioQualityMax] forKey: AVEncoderAudioQualityKey];
recorderFilePath = [NSString stringWithFormat:#"%#/MySound.caf", DOCUMENTS_FOLDER] ;
NSLog(#"recorderFilePath: %#",recorderFilePath);
NSURL *url = [NSURL fileURLWithPath:recorderFilePath];
err = nil;
NSData *audioData = [NSData dataWithContentsOfFile:[url path] options: 0 error:&err];
if(audioData)
{
NSFileManager *fm = [NSFileManager defaultManager];
[fm removeItemAtPath:[url path] error:&err];
}
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];
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];
return;
}
// start recording
[recorder recordForDuration:(NSTimeInterval) 2];
lblStatusMsg.text = #"Recording...";
selector:#selector(handleTimer) userInfo:nil repeats:YES];
}
This is my Code of MPMusicPlayer and AVAudioRecorder.Please help.Thanks in advance.
You can't record Songs imported from iPod library, you can only record mp3 file, for that you need to convert Mediaitem into mp3 format.
you can get referance for that from here, i hope this may help you.
Maybe look into playing two tracks simultaneously. You could record a separate voice over track and trigger this and your mp3 to start playing at the same time. Obviously this would only work inside your app.
My iPhone app uses "AVAudioRecorder" to make voice recordings. It also uses "UIImagePickerController" to record movies and "MPMoviePlayerController" to play movies.
Everything works fine until I do all three things in a row:
Record a movie using UIImagePickerController
Play back the recorded movie using MPMoviePlayerController
Try to make a voice recording using AVAudioRecorder
When I call AVAudioRecorder's "record" method in step 3, it returns NO indicating failure, but giving no hints as to why (come on Apple!) AVAudioRecorder's audioRecorderEncodeErrorDidOccur delegate method is never called and I receive no other errors when setting up the recorder.
My first guess was that the movie recording/playing was modifying the shared instance of "AVAudioSession" in such a way that it prevented the audio recorder from working. However, I'm manually setting AVAudioSession's category property to "AVAudioSessionCategoryRecord" and I make the audio session active before trying to record.
Here's my method for creating the recorder:
- (void)createAudioRecorder
{
NSError *error = nil;
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryRecord error:&error];
if (error)
...
[audioSession setActive:YES error:&error];
if (error)
...
NSMutableDictionary *settings = [[NSMutableDictionary alloc] init];
// General Audio Format Settings
[settings setValue:[NSNumber numberWithInt:kAudioFormatMPEG4AAC] forKey:AVFormatIDKey];
[settings setValue:[NSNumber numberWithFloat:44100.0] forKey:AVSampleRateKey];
[settings setValue:[NSNumber numberWithInt:1] forKey:AVNumberOfChannelsKey];
// Encoder Settings
[settings setValue:[NSNumber numberWithInt:AVAudioQualityMin] forKey:AVEncoderAudioQualityKey];
[settings setValue:[NSNumber numberWithInt:96] forKey:AVEncoderBitRateKey];
[settings setValue:[NSNumber numberWithInt:16] forKey:AVEncoderBitDepthHintKey];
// Write the audio to a temporary file
NSURL *tempURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:#"Recording.m4a"]];
audioRecorder = [[AVAudioRecorder alloc] initWithURL:tempURL settings:settings error:&error];
if (error)
...
audioRecorder.delegate = self;
if ([audioRecorder prepareToRecord] == NO)
NSLog(#"Recorder fails to prepare!");
[settings release];
}
And here's my method to start recording:
- (void)startRecording
{
if (!audioRecorder)
[self createAudioRecorder];
NSError *error = nil;
[[AVAudioSession sharedInstance] setActive:YES error:&error];
if (error)
...
BOOL recording = [audioRecorder record];
if (!recording)
NSLog(#"Recording won't start!");
}
Has anyone run into this problem before?
I was having the same issue. Before I fixed the issue, my recording/playback code was like this:
Start Recording Function
- (BOOL) startRecording {
#try {
NSDictionary *recordSetting = [[NSDictionary alloc] initWithObjectsAndKeys:
[NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey, [NSNumber numberWithFloat: 44100.0], AVSampleRateKey, [NSNumber numberWithInt: 1], AVNumberOfChannelsKey, [NSNumber numberWithInt: AVAudioQualityMax], AVEncoderAudioQualityKey, nil];
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *soundFilePath = [documentsPath stringByAppendingPathComponent:#"recording.caf"];
if(audioRecorder != nil) {
[audioRecorder stop];
[audioRecorder release];
audioRecorder = nil;
}
NSError *err = nil;
audioRecorder = [[AVAudioRecorder alloc] initWithURL:soundFileURL settings:recordSetting error:&err];
[soundFileURL release];
[recordSetting release];
if(!audioRecorder || err){
NSLog(#"recorder initWithURL: %# %d %#", [err domain], [err code], [[err userInfo] description]);
return NO;
}
[audioRecorder peakPowerForChannel:8];
[audioRecorder updateMeters];
audioRecorder.meteringEnabled = YES;
[audioRecorder record];
}
#catch (NSException * e) {
return NO;
}
recording = YES;
return YES;
}
Stop Recording Function
- (BOOL) stopRecording {
#try {
[audioRecorder stop];
[audioRecorder release];
audioRecorder = nil;
recording = NO;
}
#catch (NSException * e) {
return NO;
}
return YES;
}
Start Playing Function
- (BOOL) startPlaying {
#try {
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *soundFilePath = [documentsPath stringByAppendingPathComponent:#"recording.caf"]; NSURL * soundFileURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];
NSError *err = nil;
if (audioPlayer) {
[audioPlayer release];
audioPlayer = nil;
}
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL error: &err];
[soundFileURL release];
if (!audioPlayer || err) {
NSLog(#"recorder: %# %d %#", [err domain], [err code], [[err userInfo] description]);
return NO;
}
[audioPlayer prepareToPlay];
[audioPlayer setDelegate: self];
[audioPlayer play];
playing = YES;
}
#catch (NSException * e) {
return NO;
}
return YES;
}
Stop Playing Function
- (BOOL) stopPlaying {
#try {
[audioPlayer stop];
[audioPlayer release];
audioPlayer = nil;
playing = NO;
}
#catch (NSException * e) {
return NO;
}
return YES;
}
I fixed the recording issue after playing a captured video, the code is as follows:
- (BOOL) startRecording {
#try {
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryRecord error:nil];
// rest of the recording code is the same .
}
- (BOOL) stopRecording {
#try {
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayback error:nil];
// rest of the code is the same
}
- (BOOL) startPlaying {
#try {
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayback error:nil];
// rest of the code is the same.
}
- (BOOL) stopPlaying {
// There is no change in this function
}
Had the same problem. My Solution was to STOP the movie before starting the recording session. My code was similar to rmomin's code.
I've been having the same problem. I use AVPlayer to play compositions (previous recordings I've used AVAudioRecord for). However, I found that once I've used AVPlayer I could no longer use AVAudioRecorder. After some searching, I discovered that so long as AVPlayer is instantiated in memory and has been played at least once (which is usually what you do immediately after instantiating it) AVAudioRecorder will not record. However, once AVPlayer is dealloc'd, AVAudioRecorder is then free to record again. It appears that AVPlayer holds on to some kind of connection that AVAudioRecorder needs, and it's greedy...it won't let it go until you pry it from it's cold dead hands.
This is the solution I've found. Some people claim that instantiating AVPlayer takes too much time to keep breaking down and setting back up. However, this is not true. Instantiating AVPlayer is actually quite trivial. So also is instantiating AVPlayerItem. What isn't trivial is loading up AVAsset (or any of it's subclasses). You really only want to do that once. They key is to use this sequence:
Load up AVAsset (for example, if you're loading from a file, use AVURLAsset directly or add it to a AVMutableComposition and use that) and keep a reference to it. Don't let it go until you're done with it. Loading it is what takes all the time.
Once you're ready to play: instantiate AVPlayerItem with your asset, then AVPlayer with the AVPlayerItem and play it. Don't keep a reference to AVPlayerItem, AVPlayer will keep a reference to it and you can't reuse it with another player anyway.
Once it's done playing, immediately destroy AVPlayer...release it, set its var to nil, whatever you need to do. **
Now you can record. AVPlayer doesn't exist, so AVAudioRecorder is free to do its thing.
When you're ready to play again, re-instantiate AVPlayerItem with the asset you've already loaded & AVPlayer. Again, this is trivial. The asset has already been loaded so there shouldn't be a delay.
** Note that destroying AVPlayer may take more than just releasing it and setting its var to nil. Most likely, you've also added a periodic time observer to keep track of the play progress. When you do this, you receive back an opaque object you're supposed to hold on to. If you don't remove this item from the player AND release it/set it to nil, AVPlayer will not dealloc. It appears that Apple creates an intentional retain cycle you must break manually. So before you destroy AVPlayer you need to (example):
[_player removeTimeObserver:_playerObserver];
[_playerObserver release]; //Only if you're not using ARC
_playerObserver = nil;
As a side note, you may also have set up NSNotifications (I use one to determine when the player has completed playing)...don't forget to remove those as well.
I had the same problem in Monotouch and adjusted rmomins answer for Monotouch.
changed
avrecorder.Record();
to
NSError error;
var avsession = AVAudioSession.SharedInstance();
avsession.SetCategory(AVAudioSession.CategoryRecord,out error);
avrecorder.Record();
Works like a charm.
I had the same problem to record and play. To fix the problem I recall AVAudioSession in the "record" and "play" function.
This can may be help to person who has this problem on the device and not on the simulator!
I got the same problem. Finally I found out that ARC has released my recorder. So, you must declare the recorder in your .h file, i.e. AVAudioRecord *recorder;. Put other things to .m will work as normal.
I've got a button the user tap to start recording and tap again to stop. When it stop I want the recorded voice 'echo' back so the user can hear what was recorded. This works fine the first time. If I hit the button for the third time, it starts a new recording and when I hit stop it crashes with EXC_BAD_ACCESS.
- (IBAction) readToMeTapped {
if(recording)
{
recording = NO;
[readToMeButton setTitle:#"Stop Recording" forState: UIControlStateNormal ];
NSMutableDictionary *recordSetting = [[NSDictionary alloc] initWithObjectsAndKeys:
[NSNumber numberWithFloat: 44100.0], AVSampleRateKey,
[NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey,
[NSNumber numberWithInt: 1], AVNumberOfChannelsKey,
[NSNumber numberWithInt: AVAudioQualityMax], AVEncoderAudioQualityKey,
nil];
// Create a new dated file
NSDate *now = [NSDate dateWithTimeIntervalSinceNow:0];
NSString *caldate = [now description];
recordedTmpFile = [NSURL fileURLWithPath:[[NSString stringWithFormat:#"%#/%#.caf", DOCUMENTS_FOLDER, caldate] retain]];
error = nil;
recorder = [[ AVAudioRecorder alloc] initWithURL:recordedTmpFile settings:recordSetting error:&error];
[recordSetting release];
if(!recorder){
NSLog(#"recorder: %# %d %#", [error domain], [error code], [[error userInfo] description]);
UIAlertView *alert =
[[UIAlertView alloc] initWithTitle: #"Warning"
message: [error localizedDescription]
delegate: nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
return;
}
NSLog(#"Using File called: %#",recordedTmpFile);
//Setup the recorder to use this file and record to it.
[recorder setDelegate:self];
[recorder prepareToRecord];
[recorder recordForDuration:(NSTimeInterval) 5]; //recording for a limited time
}
else
{ // it crashes the second time it gets here!
recording = YES;
NSLog(#"Recording YES Using File called: %#",recordedTmpFile);
[readToMeButton setTitle:#"Start Recording" forState:UIControlStateNormal ];
[recorder stop]; //Stop the recorder.
//playback recording
AVAudioPlayer * newPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:recordedTmpFile error:&error];
[recordedTmpFile release];
self.aPlayer = newPlayer;
[newPlayer release];
[aPlayer setDelegate:self];
[aPlayer prepareToPlay];
[aPlayer play];
}
}
- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)sender successfully:(BOOL)flag {
NSLog (#"audioRecorderDidFinishRecording:successfully:");
[recorder release];
recorder = nil;
}
Checking the debugger, it flags the error here
#synthesize aPlayer, recorder;
This is the part I don't understand. I thought it may have something to do with releasing memory but I've been careful. Have I missed something?
After working on it for a while I stumbled on this debugging tip. It showed me that AVAudioPlayer was deallocated the second time around, causing the crash. So the Delegate must have done the clean up? I checked this SO thread and it is suggestion that the Delegate does not deallocate. However, if I remove the line
[newPlayer release];
My program works! After reading this SO thread, I believe my issue is that I should implement AVAudioPlayerDelegate's - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag method and release the audio player there, after the sound is done playing. I had done it for AVAudioRecorder.
Did you make sure that #property (retain) does not include nonatomic? I'm thinking that some of the code that accesses those properties may be doing so from another thread. Also, you should always access those properties via their getters by using self.recorder and self.player, in order to make sure they are accessed within their respective locks.