1

I found this great thread here on StackOverflow and used it to write my switchCamera function in Swift.

I've got it working so that when I press my button, the camera switches to the Back camera. However, it does not switch back to the Front camera once I press it again. What did I do wrong in my code that doesn't allow the camera to be switched again?

One extra note: When I translated the code mentioned in the the thread above, I was unable to return nil in my cameraWithPosition(). Not sure if that's what is causing my issue.

My Code:

@IBAction func switchCamera(sender: UIButton) {
    let currentCameraInput: AVCaptureInput = session.inputs[0] as! AVCaptureInput
    session.removeInput(currentCameraInput)

    let newCamera: AVCaptureDevice?
    if(captureDevice!.position == AVCaptureDevicePosition.Back){
        println("Setting new camera with Front")
        newCamera = self.cameraWithPosition(AVCaptureDevicePosition.Front)
    } else {
        println("Setting new camera with Back")
        newCamera = self.cameraWithPosition(AVCaptureDevicePosition.Back)
    }

    let newVideoInput = AVCaptureDeviceInput(device: newCamera!, error: nil)
    if(newVideoInput != nil) {
        session.addInput(newVideoInput)
    } else {
        println("Error creating capture device input")
    }

    session.commitConfiguration()

}

func cameraWithPosition(position: AVCaptureDevicePosition) -> AVCaptureDevice {
    let devices = AVCaptureDevice.devices()
    for device in devices {
            if(device.position == position){
                return device as! AVCaptureDevice
            }
    }
    return AVCaptureDevice()
}
Community
  • 1
  • 1
justColbs
  • 1,504
  • 2
  • 18
  • 28

2 Answers2

2

5 Minutes after I post the question and I figure it out, lol.

My issue was that I did not set my initial captureDevice equal to the newly created AVCaptureDevice which I called newCamera.

So to fix that I simply did this at the end of switchCamera()...

captureDevice! = newCamera!
justColbs
  • 1,504
  • 2
  • 18
  • 28
2

The way you implemented the toggle camera is just ok and only works if you have only one video AVCaptureDevice input. Think in the case of having multiple AVCaptureDevice inputs(audio and video). In that case you can't guarantee below line -:

 let currentCameraInput: AVCaptureInput = session.inputs[0] as! AVCaptureInput
 session.removeInput(currentCameraInput) 

In this case When you click on toggleCamera button , it crashes with below error

Couldn't add back facing video input
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** Multiple audio/video AVCaptureInputs are not currently supported.'
*** First throw call stack:
(0x38f2f2a3 0x3725997f 0x39aff977 0x39aff091 0xe943d 0xe7875 0x3a4de0a5 0x3a4de057 0x3a4de035 0x3a4dd8eb 0x3a4ddde1 0x3a4065f1 0x3a3f3801 0x3a3f311b 0x37cad5a3 0x37cad1d3 0x38f04173 0x38f04117 0x38f02f99 0x38e75ebd 0x38e75d49 0x37cac2eb 0x3a4472f9 0xdf1ab 0x36324b20)

To overcome this issue i have implemented it different way. So mine toggle camera code inside CameraController.swift looks like this -:

// toggleCamera basic purpose is to toggle the camera from front to back or vice versa as per user selection

func toggleCamera(){
        println("toggleCamera -----")
        var error:NSError?
        var backCameraDevice:AVCaptureDevice?
        var audio:AVCaptureDevice?
        var frontCameraDevice:AVCaptureDevice?
        var rearCamera: AVCaptureInput?
        var frontCamera: AVCaptureInput?
        for device in availableCameraDevices as! [AVCaptureDevice] {
           if device.position == .Back {
            self.backCameraDevice = device
           }
           else if device.position == .Front {
            self.frontCameraDevice = device
           }
        }

        if let validVideoFrontDevice = self.frontCameraDevice {
                self.frontCamera = AVCaptureDeviceInput.deviceInputWithDevice(validVideoFrontDevice, error: &error) as! AVCaptureDeviceInput
        }

        if let validVideoBackDevice = self.backCameraDevice {
                self.rearCamera = AVCaptureDeviceInput.deviceInputWithDevice(validVideoBackDevice, error: &error) as! AVCaptureDeviceInput
        }

        session.beginConfiguration()
        let inputs = session.inputs as! [AVCaptureInput]
        let newCamera: AVCaptureDevice?
        if(currentCameraDevice!.position == AVCaptureDevicePosition.Back){
            println("Setting new camera with Front")
            newCamera = self.frontCameraDevice
            if self.hasFrontCamera {
                if let validBackDevice = self.rearCamera {
                    if contains(inputs, validBackDevice) {
                        session.removeInput(validBackDevice)
                    }
                }
                if let validFrontDevice = self.frontCamera {
                    if !contains(inputs, validFrontDevice) {
                        session.addInput(validFrontDevice)
                    }
                }
            }
        } else {
            println("Setting new camera with Back")
            newCamera = self.backCameraDevice
            if let validFrontDevice = self.frontCamera {
                if contains(inputs, validFrontDevice) {
                    session.removeInput(validFrontDevice)
                }
            }
            if let validBackDevice = self.rearCamera {
                if !contains(inputs, validBackDevice) {
                    session.addInput(validBackDevice)
                }
            }
        }
        session.commitConfiguration()
        if let validError = error {
            println("Device setup error occured \(validError.localizedDescription)")
        }
        currentCameraDevice! = newCamera!
}

    /// The Bool property to determine if current device has front camera.

public var hasFrontCamera: Bool = {
        let devices = AVCaptureDevice.devicesWithMediaType(AVMediaTypeVideo)
        for  device in devices  {
            let captureDevice = device as! AVCaptureDevice
            if (captureDevice.position == .Front) {
                return true
            }
        }
        return false
        }()

In my view controller:

@IBAction func toggleCamera(sender: UIButton) {
    //  toggle the camera side
    println("toggling the camera side")
    self.cameraController.toggleCamera()
}

Hope it helps. Thanks

Vivek Parihar
  • 2,318
  • 18
  • 18