1

Update

I'm starting to figure this out. The AVAudioRecorder session gets activated and I get mic level readings for a few seconds. Then the async video code completes, the camera view displays, and I stop getting readings. It seems like the video is killing the audio session.

What's strange is that the code works on iOS 7 and won't work on iOS 6. Any ideas how to get around this. Is it a limitation on iOS 6?

I'm getting sound levels via the mic and I can only get them when I place a breakpoint on the code that sets up my audio recorder object. If I run without pausing at that point for a few seconds it can't get the levels. This code is in viewDidLoad and is and I can place the breakpoint on one of those first 3 lines:

_recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error];
[_recorder prepareToRecord];
_recorder.meteringEnabled = YES;

    _levelTimer = [NSTimer scheduledTimerWithTimeInterval: 0.03 target: self selector: @selector(levelTimerCallback) userInfo: nil repeats: YES];

I get my levels in the levelTimerCallback method.

This code goes in viewDidAppear:

    NSError *error;

if (_recorder) {
    [_recorder record];
} else
    NSLog(@"Error: %@", [error description]);

Edit:

levelTimerCallback code:

    [_recorder updateMeters];

const double ALPHA = 0.05;
double peakPowerForChannel = pow(10, (0.05 * [_recorder peakPowerForChannel:0]));
_lowPassResults = ALPHA * peakPowerForChannel + (1.0 - ALPHA) * _lowPassResults;

NSLog(@"Average input: %f Peak input: %f", [_recorder averagePowerForChannel:0], [_recorder peakPowerForChannel:0]);

Async code run above recorder code:

            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [[[self captureManager] session] startRunning];
        });

Camera code:

    if ([self captureManager] == nil) {
    AVCamCaptureManager *manager = [[AVCamCaptureManager alloc] init];
    [self setCaptureManager:manager];

    [[self captureManager] setDelegate:self];

    if ([[self captureManager] setupSession]) {
        // Create video preview layer and add it to the UI
        AVCaptureVideoPreviewLayer *newCaptureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:[[self captureManager] session]];
        UIView *view = [self videoPreviewView];
        CALayer *viewLayer = [view layer];
        [viewLayer setMasksToBounds:YES];

        CGRect bounds = [view bounds];
        [newCaptureVideoPreviewLayer setFrame:bounds];

        if ([[newCaptureVideoPreviewLayer connection] isVideoOrientationSupported]) {
            [[newCaptureVideoPreviewLayer connection] setVideoOrientation:AVCaptureVideoOrientationPortrait];
        }

        [newCaptureVideoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];

        [viewLayer insertSublayer:newCaptureVideoPreviewLayer below:[[viewLayer sublayers] objectAtIndex:0]];

        [self setCaptureVideoPreviewLayer:newCaptureVideoPreviewLayer];

        // Start the session. This is done asychronously since -startRunning doesn't return until the session is running.
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [[[self captureManager] session] startRunning];
        });


        [self addObserver:self forKeyPath:@"captureManager.videoInput.device.focusMode" options:NSKeyValueObservingOptionNew context:AVCamFocusModeObserverContext];

        // Add a single tap gesture to focus on the point tapped, then lock focus
        UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapToAutoFocus:)];
        [singleTap setDelegate:self];
        [singleTap setNumberOfTapsRequired:1];
        [view addGestureRecognizer:singleTap];

        // Add a double tap gesture to reset the focus mode to continuous auto focus
        UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapToContinouslyAutoFocus:)];
        [doubleTap setDelegate:self];
        [doubleTap setNumberOfTapsRequired:2];
        [singleTap requireGestureRecognizerToFail:doubleTap];
        [view addGestureRecognizer:doubleTap];
    }
}

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

AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setActive: YES error: nil];

[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryRecord error: nil];

NSError *error;
_recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error];
4

1 回答 1

1

我相信您应该改为_levelTimer = [NSTimer scheduledTimerWithTimeInterval: 0.03 target: self selector: @selector(levelTimerCallback) userInfo: nil repeats: YES]; 在末尾调用viewDidAppear,然后将其 nil 并在viewDidDisappear. viewDidLoad当您在viewDidAppear. 您可能还想检查是否使用主线程而不是后台线程[[[self captureManager] session] startRunning];

于 2013-09-05T17:13:26.870 回答