AVAudioRecorder woes on MacOSX - objective-c

I'm attempting to use AVAudioRecorder on MacOSX 10.14.x to get audio level readings of an input source -- in this case, the microphone. As this isn't on iOS, the use of AVAudioSession does not apply. I did enable the microphone in the SandBox settings, as well as double-checking everything in Audio Midi Setup app, with the microphone set to 2ch 24-bit Integer 44.1kHz. I've removed all error checking, but everything should be fine (eg. apparent success on all calls to the recorder object). Also, I tried this on another 10.14.x machine with the same result.
When I run this, all I get is values of -120.0 for both the average and peak power in my callback, even if there is audio.
Any idea what I'm doing wrong?
Note: When I initiate [recorder prepareToRecord], I receive these two error messages:
no saved enable hardware sample rate converter preference found
ca_debug_string: inPropertyData == NULL
AVAudioRecorder *recorder; // instance variable
NSTimer *levelTimer; // instance variable
NSURL *url = [NSURL fileURLWithPath: #"/dev/null"];
NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithFloat: 44100.00], AVSampleRateKey,
[NSNumber numberWithInt: kAudioFormatMPEG4AAC], AVFormatIDKey,
[NSNumber numberWithInt: 1], AVNumberOfChannelsKey,
[NSNumber numberWithInt: AVAudioQualityHigh], AVEncoderAudioQualityKey,
nil];
NSError *error = nil;
recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error];
[recorder prepareToRecord];
recorder.meteringEnabled = YES;
[recorder record];
levelTimer = [NSTimer scheduledTimerWithTimeInterval:0.03
target:self
selector:#selector(levelTimerCallback:)
userInfo:nil
repeats:YES];
- (void)levelTimerCallback:(NSTimer *)timer {
[recorder updateMeters];
float peakPower = [recorder peakPowerForChannel:0];
float avgPower = [recorder averagePowerForChannel:0];
}

Related

AVAudioRecorder stops working when writing to /dev/null on iPhone 5s with iOS 7

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];

AVRecorder is delay when back from background mode?

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?

Strange Error when using AVAudioRecorder with MPEG4AAC

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

AVAudioRecorder error "playback data format is unsupported" on iOS?

The code below is throwing an OSStatus error 1718449215 which, according to the Audio Queue Reference, represents "The playback data format is unsupported."
The code works correctly if I change the AVFormatKey to be kAudioFormatiLBC or kAudioFormatLinearPCM. Is recording using kAudioFormatMPEG4AAC_HE supported on iOS?
NSDictionary *settings =
[NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithFloat: 32000.0], AVSampleRateKey,
[NSNumber numberWithInt: kAudioFormatMPEG4AAC_HE], AVFormatIDKey,
[NSNumber numberWithInt: 1], AVNumberOfChannelsKey,
[NSNumber numberWithInt: AVAudioQualityMedium], AVEncoderAudioQualityKey,
nil];
NSError *error = nil;
AVAudioRecorder *avRecorder = [[AVAudioRecorder alloc]
initWithURL:url
settings:settings
error:&error];
NSAssert(error.code != 1718449215, #"The playback data format is unsupported.");
The Apple docs, specifically the Multimedia Programming Guide ( http://developer.apple.com/library/ios/#documentation/AudioVideo/Conceptual/MultimediaPG/UsingAudio/UsingAudio.html ), only lists the HE-AAC as a playback format. Regular AAC is listed for both playback and recording. So, it looks like HE-AAC only has partial support.

IOS AVAudioRecorder updatemeters seems not update on device, works on simulator

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];