Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AVAudioRecorder averagePowerForChannel always returns -120.0

I'm trying to use AVAudioRecorder's averagePowerForChannel method to monitor input levels on the microphone for an iPad/iPhone app. I have a callback which polls the average level in a loop — on the iPhone it works fine and returns sensible levels, but for some reason on the iPad it always returns -120.0.

Here's some of my setup code:

- (void) setupMic {
if (micInput) {
    [micInput release];
    micInput = nil;
}
NSURL *newURL = [[NSURL alloc] initFileURLWithPath:@"/dev/null"];

NSMutableDictionary *recordSettings = [[NSMutableDictionary alloc] init];

[recordSettings setObject:[NSNumber numberWithInt:kAudioFormatAppleLossless] forKey: AVFormatIDKey];
[recordSettings setObject:[NSNumber numberWithFloat:22050.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: AVAudioQualityLow] forKey: AVEncoderAudioQualityKey];

micInput = [[AVAudioRecorder alloc] initWithURL:newURL settings:recordSettings error:nil];
//  [micInput setMeteringEnabled:YES];

[newURL release];
[recordSettings removeAllObjects];
[recordSettings release];
}

As well as my start recording method:

- (void) startRecording {
NSLog(@"startRecording!");
[micInput pause];
[micInput prepareToRecord];
micInput.meteringEnabled = YES;
[micInput record];
[micInput updateMeters];
levelTimer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:0.0] interval:0.03 target:self selector:@selector(levelTimerCallback:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:levelTimer forMode:NSDefaultRunLoopMode];
}

and a bit of the levelTimer callback:

- (void)levelTimerCallback:(NSTimer *)timer {
[micInput updateMeters];
double avgPowerForChannel = pow(10, (0.05 * [micInput averagePowerForChannel:0]));
[micSprite receiveInput:avgPowerForChannel];

NSLog(@"Avg. Power: %f", [micInput averagePowerForChannel:0]);

 ...

}

Where on the iPhone, the NSLog statement will return sensible values, and the iPad will always return -120.0.

Note: I'm using this inside of a cocos2d application. For some reason, if I restart the current scene on the iPad, the mic levels will return correct values.

Anyone have any suggestions? I'm seriously at a loss here. Thanks!

like image 562
chmod Avatar asked Feb 16 '11 21:02

chmod


2 Answers

I had the same issue. I found setting the category to AVAudioSessionCategoryPlayAndRecord fixes it:

NSError *error;
[[AVAudioSession sharedInstance] 
    setCategory:AVAudioSessionCategoryPlayAndRecord error:&error];

if (error) {
    NSLog(@"Error setting category: %@", [error description]);
}
like image 65
Richard Caetano Avatar answered Oct 18 '22 01:10

Richard Caetano


Yes, I did too. There is only one shared AVAudioSession. Setting its category affects all recorders and players, so setting the category to AVAudioSessionCategoryPlay in one area of the app for example disables recorders in other areas.

like image 26
Steve Rogers Avatar answered Oct 18 '22 03:10

Steve Rogers