开发者

AVAudioRecorder averagePowerForChannel always returns -120.0

开发者 https://www.devze.com 2023-02-10 18:26 出处:网络
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 th

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 appl开发者_开发百科ication. 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!


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


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.


Another possible cause of this is really simple, be sure you're calling [recorder record];

That line was accidentally deleted and it took us a while to recognize that as the cause of the -120 values being returned on the meter.

HTH


1) Make sure you have the permission:

if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) {
    if([[AVAudioSession sharedInstance] respondsToSelector:@selector(requestRecordPermission:)])
    {
        [[AVAudioSession sharedInstance] requestRecordPermission:^(BOOL granted) {
            NSLog(@"permission : %d", granted);
            if(granted)[self setupMic];// record ...
        }];
    }
}

2) Make sure your path is legitimate (/dev/null ok??):

NSString* dir=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSArray *pathComponents = [NSArray arrayWithObjects:dir,fileName,nil];
recordedAudioURL = [NSURL fileURLWithPathComponents:pathComponents];

3) activate audioSession

 [audioSession setActive:YES error:&error];

4) Check all errors and return values, including

BOOL ok=[micInput prepareToRecord];
ok=ok &&[micInput record];


You need to init the AVAudioSession (it should be done from didMoveToview method, it might be a reason of the problem)

let session = AVAudioSession.sharedInstance()
    try session.setCategory(AVAudioSessionCategoryPlayAndRecord)
    try session.overrideOutputAudioPort(AVAudioSessionPortOverride.speaker)
    try session.setActive(true)
try recorder = AVAudioRecorder(url: getDocumentsDirectory(), settings: settings)

and start recorder

func start() {
    recorder?.record()
    recorder?.updateMeters()
}

And get the decibels by calling

let decibels = recorder.averagePower(forChannel: 0)

from -120 (min value) up to 0. Noice level of some cafe for example is -20

here's the more detailed example http://www.mikitamanko.com/blog/2017/04/15/swift-how-to-get-decibels/ Note: use the update method as well.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号