Search code examples
iosobjective-cunity-game-enginevuforia

Unity Vuforia Extension EXC_BAD_ACCESS with AVCaptureSession


So I am using Unity 2017.2.0f3 with the Vuforia Extension, and I imported the project in an extant iOS project following the https://github.com/blitzagency/ios-unity5 tutorial. The extant iOS project included a view in which you can toggle between an AR view which uses Vuforia, and a native iOS AVCaptureSession which can scan barcodes. The former works without error, but as soon as I try to do session.addInput or session.addOutput the latter feature crashes with:

EXC_BAD_ACCESS

within the com.apple.avfoundation.videodataoutput.bufferqueue Queue. I tried to use NSZombie to learn more about what kind of object was trying to be sent a message, but i can only run the application on a physical device, and thus I can't learn more about the actual object it tries to send a message to which causes the crash.

My reasoning is that it may have to do with Vuforia persisting a reference to a freed VIdeoDataOutput Buffer Queue which is triggered by my creation of a new AVCaptureSession with an AVCaptureOutput and an AVCaptureInput. What is tricky is that I don't know how to actually ascertain this or not since it is a third party library. The only ViewController which has an Objective-C wrapper is called CameraCapture.mm but this seems to be a vestigial Unity only View Controller, since any NSLogs or breakpoints I put in that method are not called.

private func setupCamera() {
    guard let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo),
        let input = try? AVCaptureDeviceInput(device: device) else {
            return
    }

    if session.canAddInput(input) {
        session.addInputWithNoConnections(input)
    }

    previewLayer = AVCaptureVideoPreviewLayer(session: session)
    previewLayer.frame = self.view.bounds
    previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
    view.layer.addSublayer(previewLayer)
    cameraPreviewView.layer.addSublayer(previewLayer)
    let metadataOutput = AVCaptureMetadataOutput()

    if session.canAddOutput(metadataOutput) {
        session.addOutputWithNoConnections(metadataOutput)

        metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
        metadataOutput.metadataObjectTypes = metadataOutput.availableMetadataObjectTypes
    } else {
        print("Could not add metadata output")
    }
}

Once the above method is called, even after calling the AppDelegate function from the blitz tutorial appDelegate.stopUnity() always crashes the app.


Solution

  • So basically the error I was getting was from Unity not truly exiting when in background. This is a setting which is configurable for iOS Unity exports in Unity itself. If you go to Edit> Player Settings> and then in the Inspector on the right under Other Settings there is a field called Behavior In Background. My original export had this set to Suspend and this caused the AVCaptureSession intrinsic to a Camera in Unity/Vuforia to not be probably cleaned up, in terms of its videoOutput delegate buffer, when Unity wasn't running, thus the resulting EXC_BAD_ACCESS when thinking I had Unity stopped and starting a new AVCaptureSession. So by switching Behavior In Background to Exit and then guaranteeing in my app that I had called appDelegate.stopUnity() before doing setting up input/output pairs for a new AVCaptureSession() successfully fixed the issue.