Danilo Birbiglia
Danilo Birbiglia

Reputation: 11

Torch Freezes Ultra-Wide Camera When Switching Between Wide & Ultra-Wide (AVFoundation Bug?)

I'm working on an iOS app using AVFoundation to handle real time video capture and object detection. However, I’ve encountered a frustrating issue when switching between the Wide and Ultra Wide cameras while the torch is ON.

Issue:

  1. Is this a known limitation of AVFoundation or is there a workaround to enable the torch on Ultra-Wide?
  2. How does Apple’s default Camera app manage to enable the torch with Ultra Wide without crashing?
  3. What’s the correct approach to avoid the camera freezing when toggling between Wide and Ultra Wide with the torch active?
  4. Is there a proper way to synchronize torch activation with camera switching in AVFoundation?

Current Code (Torch + Camera Switch)

@IBAction func ultrawideCameraTapped(_ sender: Any?) {
    DispatchQueue.global(qos: .userInitiated).async { [weak self] in
        guard let self = self else { return }

        let isSwitchingToUltraWide = !self.isUsingFisheyeCamera
        let cameraType: AVCaptureDevice.DeviceType = isSwitchingToUltraWide ? .builtInUltraWideCamera : .builtInWideAngleCamera
        let cameraName = isSwitchingToUltraWide ? "Ultra Wide" : "Wide"

        guard let selectedCamera = AVCaptureDevice.default(cameraType, for: .video, position: .back) else {
            DispatchQueue.main.async {
                self.showAlert(title: "Camera Error", message: "\(cameraName) camera is not available on this device.")
            }
            return
        }

        do {
            let currentInput = self.videoCapture.captureSession.inputs.first as? AVCaptureDeviceInput

            self.videoCapture.captureSession.beginConfiguration()

            // If switching to Ultra-Wide with Torch ON, attempt workaround
            if isSwitchingToUltraWide && self.isFlashlightOn {
                self.forceEnableTorchThroughWide()
            }

            if let currentInput = currentInput {
                self.videoCapture.captureSession.removeInput(currentInput)
            }

            let videoInput = try AVCaptureDeviceInput(device: selectedCamera)
            self.videoCapture.captureSession.addInput(videoInput)

            self.videoCapture.captureSession.commitConfiguration()

            self.videoCapture.updateVideoOrientation()

            DispatchQueue.main.async {
                if let barButton = sender as? UIBarButtonItem {
                    barButton.title = isSwitchingToUltraWide ? "Wide" : "Ultra Wide"
                    barButton.tintColor = isSwitchingToUltraWide ? UIColor.systemGreen : UIColor.white
                }
                print("Switched to \(cameraName) camera.")
            }

            self.isUsingFisheyeCamera.toggle()
        } catch {
            DispatchQueue.main.async {
                self.showAlert(title: "Camera Error", message: "Failed to switch to \(cameraName) camera: \(error.localizedDescription)")
            }
        }
    }
}

func forceEnableTorchThroughWide() {
    DispatchQueue.global(qos: .userInitiated).async {
        guard let wideCamera = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back), wideCamera.hasTorch else {
            DispatchQueue.main.async {
                self.showAlert(title: "Torch Error", message: "Torch is not available on this device.")
            }
            return
        }

        do {
            try wideCamera.lockForConfiguration()
            wideCamera.torchMode = .on
            self.isFlashlightOn = true
            wideCamera.unlockForConfiguration()
        } catch {
            DispatchQueue.main.async {
                self.showAlert(title: "Torch Error", message: "Error while forcing torch through Wide Camera: \(error.localizedDescription)")
            }
        }
    }
}

Upvotes: 1

Views: 50

Answers (0)

Related Questions