I have CaptureDelegate that has a method setupCaptureDevice that I call from .task:
class CaptureDelegate: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate, ObservableObject {
let captureSession = AVCaptureSession() // For capturing what comes in from the device's camera
let captureSessionQueue = DispatchQueue(label: "captureSessionQueue") // For processing images
@Published var cameraIsActive: Bool = false
func setupCaptureSession(captureDevice: AVCaptureDevice?) {
let videoCaptureDevice: AVCaptureDevice
if let captureDevice {
videoCaptureDevice = captureDevice
} else {
//will pick the best camera or the only camera(for iphone SE)
if let device = AVCaptureDevice.default(.builtInDualCamera,
for: .video, position: .back) {
videoCaptureDevice = device
} else if let device = AVCaptureDevice.default(.builtInWideAngleCamera,
for: .video, position: .back) {
videoCaptureDevice = device
} else {
fatalError("Missing expected back camera device.")
}
}
guard let videoDeviceInput = try? AVCaptureDeviceInput(device: videoCaptureDevice) else { //input from the back Camera
print( "Failed to create AVCaptureDeviceInput")
return
}
let videoOutput = AVCaptureVideoDataOutput() //the output that camera catches
videoOutput.setSampleBufferDelegate(self, queue: captureSessionQueue)
captureSession.beginConfiguration( )
if captureSession.canAddInput(videoDeviceInput) {
captureSession.addInput(videoDeviceInput)
} else {
print("Failed to add input to capture session")
}
if captureSession.canAddOutput(videoOutput) {
captureSession.addOutput(videoOutput)
} else {
print("Failed to add output to capture session")
}
captureSession.sessionPreset = .high
captureSession.commitConfiguration() //commit the new frames to CaptureSession
DispatchQueue.global().async {
self.captureSession.startRunning()
}
it takes an optional AVCaptureDevice so that the first time the app runs it initiates with the back camera. I want to allow the user to toggle from back to front and vice verse so I am attempting to have a published property that the user can toggle via a method call In CaptureDelegate:
@Published var currentCamera: AVCaptureDevice?
//Switch from front to back camera etc
func toggleCaptureDevice() {
captureSession.stopRunning()
//Now define the AVCapturedevice, switch to back cam if it is front and switch to front cam if its back
//Now call setupCaptureSession but this time actually pass in that device
}
}
My problem is how do I know if the App is currently using the front or back camera to be able to toggle it and update my currentCamera?
I think what you need is: AVCaptureDeviceInput.position
@Published var currentCameraPosition: AVCaptureDevice.Position = .back
func toggleCaptureDevice() {
captureSessionQueue.async { [weak self] in
guard let self = self else { return }
self.captureSession.beginConfiguration()
if let currentInput = self.captureSession.inputs.first as? AVCaptureDeviceInput {
self.captureSession.removeInput(currentInput)
}
let newPosition: AVCaptureDevice.Position = (self.currentCameraPosition == .back) ? .front : .back
guard let newDevice = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: newPosition) else {
print("Failed to get new camera device")
return
}
do {
let newInput = try AVCaptureDeviceInput(device: newDevice)
if self.captureSession.canAddInput(newInput) {
self.captureSession.addInput(newInput)
self.currentCameraPosition = newPosition // Update camera state
} else {
print("Failed to add new input to capture session")
}
} catch {
print("Error switching camera: \(error)")
}
self.captureSession.commitConfiguration()
self.captureSession.startRunning()
}
}