i am using a lot the AVRecorder and AVPlayer.
i saw that they both , delay when i am back to my app ,after she was on background- then if for example i am trying to record , it takes 4 seconds till it starts .
in my code, i am preparing to record before i am recording, but when back to app, it doesnt help .
what can i do to improve it ?
this is done when app is open(at the start, not when back from background! )
-(void)prepareToRecord
{
NSArray *dirPaths;
NSString *docsDir;
NSString *sound=[NSString stringWithFormat:#"sound%d.caf",[memoryInstnace getNextFreePlace]];
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) ;
docsDir = [dirPaths objectAtIndex:0];
currentSoundFilePath = [docsDir stringByAppendingPathComponent:sound];
NSURL *soundFileURL = [NSURL fileURLWithPath:currentSoundFilePath];
NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithFloat: 44100.0], AVSampleRateKey,
[NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey,
[NSNumber numberWithInt: 1], AVNumberOfChannelsKey,
[NSNumber numberWithInt: AVAudioQualityMax], AVEncoderAudioQualityKey,
nil];
NSError *error;
recorder = [[AVAudioRecorder alloc] initWithURL:soundFileURL settings:settings error:&error];
//to not having a delay befor record
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryRecord error:nil];
if (recorder)
{
[recorder prepareToRecord];
recorder.meteringEnabled = YES;
}
else
NSLog( #"error in recordings" );
}
thanks !
If another app had grabbed the control of the mic via starting an active AVAudioSession, then iOS will fade out control from that app and give it to you when you activate your session. This can take a second or two. Is this what is happening? or is something else slowing you down?
Related
I have an app that monitors the background audio level without recording to a file. I use the trick of writing to /dev/null to accomplish this.
This code has worked on the iPhone 3GS with iOS 6, iPhone 4 with iOS 6 and iOS 7, and in the simulator with iOS 7 and iPhone Retina (4-inch 64-bit).
When I try it on a real iPhone 5s, however, the recorder seems to capture audio for a moment, and then silently dies.
This is the code:
// Inititalize the audio
NSURL *url = [NSURL fileURLWithPath:#"/dev/null"];
NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithFloat: 44100.0], AVSampleRateKey,
[NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey,
[NSNumber numberWithInt: 1], AVNumberOfChannelsKey,
[NSNumber numberWithInt: AVAudioQualityMax], AVEncoderAudioQualityKey,
nil];
NSError *error;
recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error];
if (recorder) {
[recorder prepareToRecord];
recorder.meteringEnabled = YES;
[recorder record];
levelTimer = [NSTimer scheduledTimerWithTimeInterval: 0.03 target: self selector: #selector(levelTimerCallback:) userInfo: nil repeats: YES];
// peakLevelTimer = [NSTimer scheduledTimerWithTimeInterval: 2.0 target: self selector: #selector(peakLevelTimerCallback:) userInfo: nil repeats: YES];
} else {
NSLog(#"There was an error setting up the recorder.");
NSLog([error description]);
}
Any ideas what might be going on?
Could anyone suggest a workaround? Writing to a real file works, but I don't want to fill up any space on the device just to monitor audio. Is there a way to write to a small file buffer that just evaporates into thin air? Implement my own /dev/null, effectively?
I had the same issue when testing one of my apps for iOS 7.
I got around the absence of /dev/null by creating an initial file that I then deleted a number of seconds after the recording started. The recording still continued to work for my application and there was no data file being stored.
- (void)startRecording
{
// New recording path.
NSString *recorderFilePath = [NSString stringWithFormat:#"%#/%#.caf", [NSHomeDirectory() stringByAppendingPathComponent:#"Documents"], #"cache"];
NSURL *url = [NSURL fileURLWithPath:recorderFilePath];
AVAudioRecorder recorder = [[ AVAudioRecorder alloc] initWithURL:url settings:recordSetting error:&err];
if([recorder prepareToRecord])
{
[recorder record];
NSTimer deleteFileTimer = [NSTimer scheduledTimerWithTimeInterval:15 target:self selector:#selector(removeRecordingFile) userInfo:nil repeats:NO];
}
}
- (void)removeRecordingFile
{
// Remove the data file from the recording.
NSString *recorderFilePath = [NSString stringWithFormat:#"%#/%#.caf", [NSHomeDirectory() stringByAppendingPathComponent:#"Documents"], #"cache"];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error = nil;
BOOL success = [fileManager removeItemAtPath:recorderFilePath error:&error];
if(success)
{
NSLog(#"Deleted recording file");
}
else
{
NSLog(#"Could not delete file -:%# ",[error localizedDescription]);
}
}
You need to change:
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:NULL];
to:
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryRecord error:NULL];
I have tested this on two different iPad3s and on one I can record and playback both .m4a and .caf files on the other I can only playback .caf files.
What I do is record a .m4a-file using the setting
AVFormatIDKey set to kAudioFormatMPEG4AAC
On the one iPad it works fine. If I test it on the other iPad I get the error "OSStatus error 1685348671" when I try to play the file recorded.
However if I comment out that setting and record as a .caf-file it works flawlessly.
Here the relevant code snippets:
NSDictionary *recorderSettings = [NSDictionary dictionaryWithObjectsAndKeys:
//[NSNumber numberWithInt:kAudioFormatMPEG4AAC], AVFormatIDKey,
[NSNumber numberWithInt:AVAudioQualityMin], AVEncoderAudioQualityKey,
[NSNumber numberWithInt:16], AVEncoderBitRateKey,
[NSNumber numberWithInt:1], AVNumberOfChannelsKey,
[NSNumber numberWithFloat:16000.0], AVSampleRateKey, nil];
I then go and call a simple
AudioRecorder *audioRecorder = [[AVAudioRecorder alloc] initWithURL:soundFileURL settings:recorderSettings error:&error];
To play back I call
AudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL error:&error];
[audioPlayer play];
Thanks
I have 2 classes, a record and a player. In my main scene, I create an instance of them and play and record. But, as I see, it only records and somehow does not play (the file is not there!)
Here is the code for both :
-(void)record {
NSArray *dirPaths;
NSString *docsDir;
NSString *sound= #"sound0.caf" ;
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) ;
docsDir = [dirPaths objectAtIndex:0];
NSString *soundFilePath = [docsDir stringByAppendingPathComponent:sound];
NSURL *soundFileURL = [NSURL fileURLWithPath:soundFilePath];
NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithFloat: 44100.0], AVSampleRateKey,
[NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey,
[NSNumber numberWithInt: 1], AVNumberOfChannelsKey,
[NSNumber numberWithInt: AVAudioQualityMax],
AVEncoderAudioQualityKey, nil];
NSError *error;
myRecorder = [[AVAudioRecorder alloc] initWithURL:soundFileURL settings:settings error:&error];
if (myRecorder) {
NSLog(#"rec");
[myRecorder prepareToRecord];
myRecorder.meteringEnabled = YES;
[myRecorder record];
} else
NSLog( #"error" );
}
I can see the log of rec.
-(void)play {
NSArray *dirPaths;
NSString *docsDir;
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
NSString *soundFilePath1 = #"sound0.caf" ;
NSURL *soundFileURL = [NSURL fileURLWithPath:soundFilePath1];
BOOL isMyFileThere = [[NSFileManager defaultManager] fileExistsAtPath:soundFilePath1];
if(isMyFileThere) {
NSLog(#"PLAY");
avPlayer1 = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL error:NULL];
avPlayer1.volume = 8.0;
avPlayer1.delegate = self;
[avPlayer1 play];
}
}
I DONT SEE THE LOG OF PLAY !
I call them both with:
recInst=[recorder alloc]; //to rec
[recInst record];
plyInst=[player alloc]; //play
[plyInst play];
and to stop the recorder:
- (void)stopRecorder {
NSLog(#"stopRecordings");
[myRecorder stop];
//[myRecorder release];
}
What's wrong here? Thanks.
In your record method, you're appending the file name to the path with:
NSString *soundFilePath = [docsDir stringByAppendingPathComponent:#"sound0.caf"];
You do not do that in your play method, so it's looking for the file in whatever the current working directory is, rather than the Documents directory.
You need to do:
NSString *soundFilePath1 = [docsDir stringByAppendingPathComponent:#"sound0.caf"];
instead of:
NSString *soundFilePath1 = #"sound0.caf" ;
And just another note: soundFilePath and soundFilePath1 are both local variables. Therefore, they are not visible outside their respective methods. Thus, it's not necessary to give them different names. You can call them both soundFilePath and there will not be a conflict.
1) I want to make an Iphone app like Talking Tom. I have downloaded the sample example from :--> https://github.com/zoul/Finch site. It plays fine with given audio file. But I want to play my recorded file with pitch effect. My problem is when I pass my recorded file (Recorded using AVAudioRecorder) the error comes like "Failed to read sound data." please help me why this error occurs. Is there any file format problem when recording file using AVAudioRecorded or any setting problem?
my Setting code is here....
NSArray *dirPaths;
NSString *docsDir;
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
NSString *soundFilePath = [docsDir stringByAppendingPathComponent:#"sound.caf"];
soundFileURL = [NSURL fileURLWithPath:soundFilePath];
NSDictionary *recordSettings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt: AVAudioQualityMedium],AVEncoderAudioQualityKey,
[NSNumber numberWithInt:16],AVEncoderBitRateKey,
[NSNumber numberWithInt: 2],AVNumberOfChannelsKey,
[NSNumber numberWithFloat: 44100.0],AVSampleRateKey,
[NSNumber numberWithInt: kAudioFormatLinearPCM], AVFormatIDKey,
[NSNumber numberWithBool:YES],AVLinearPCMIsBigEndianKey,
nil];
NSError *error = nil;
audioRecorder = [[AVAudioRecorder alloc] initWithURL:soundFileURL settings:recordSettings error:&error];
if(error)
{
NSLog(#"error in AudioRecorder Initializing...: %#", [error localizedDescription]);
}
else
{
//audioRecorder.meteringEnabled = YES;
[audioRecorder prepareToRecord];
}
2)I found another example from http://dirac.dspdimension.com/Dirac3_Technology_Home_Page/Dirac3_Technology.html site.
In this example I can Play my recorded file but too much disturbance comes.
The sound is continuously playing after playing and not able to stop it. Sometimes app crashes when pitch changed.In this example they are using "libDIRAC_iOS4-fat.a" library. so can we use this library ? And how can we stop sound playing.
Is there any way to do this using easily ?
Thanks in advance.
bool b;
NSLog(#"url");
NSURL *url = [NSURL fileURLWithPath:#"/dev/null"];
NSLog(#"dizionario");
NSDictionary *audioSettings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithFloat: 44100.0], AVSampleRateKey,
[NSNumber numberWithInt: kAudioFormatAppleLossless], AVFormatIDKey,
[NSNumber numberWithInt: 1], AVNumberOfChannelsKey,
[NSNumber numberWithInt: AVAudioQualityMax], AVEncoderAudioQualityKey,
nil];
NSError *error;
recorder = [[AVAudioRecorder alloc] initWithURL:url settings:audioSettings error:&error];
NSLog(#"audio");
if (recorder) {
[recorder prepareToRecord];
recorder.meteringEnabled = YES;
b=[recorder record];
} else {
NSLog(#"ERRORE:");
NSLog([error description]);
}
and
[recorder updatemeters];
NSLog(#"%f",[recorder peakPowerForChannel:0]);
the mic detects the firs found (i think) because every new runs the value displayed is different, but on the same run the value is not changing at all
any ideas?
found the solution. with audioSession = [[AVAudioSession sharedInstance] retain];
[audioSession setCategory:AVAudioSessionCategoryRecord error: nil];
[audioSession setActive:YES error: nil];