iOS - Code only works when I insert a breakpoint

孤人 提交于 2019-12-08 12:31:01

问题


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

回答1:


I believe you should call _levelTimer = [NSTimer scheduledTimerWithTimeInterval: 0.03 target: self selector: @selector(levelTimerCallback) userInfo: nil repeats: YES]; at the end of viewDidAppear instead, and nil it out and invalidate it in viewDidDisappear. Having a timer firing from viewDidLoad does not make sense when you have the other code in viewDidAppear. You may also want to check using the main thread instead of the background thread for [[[self captureManager] session] startRunning];.



来源:https://stackoverflow.com/questions/18641706/ios-code-only-works-when-i-insert-a-breakpoint

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!