Post

Replies

Boosts

Views

Activity

Reply to Telephoto Lens Keeps Switching to Other Lenses on iPhone 16 Pro Max During PPG (Finger on Camera)
Hi Greg @DTS Engineer , Thanks again for your response. I understand the value of a focused sample project, but to save time, I’ve included an expanded and representative code snippet directly from my CameraManager. I hope this helps clarify what I’m doing. In this feature, the user places a finger over the telephoto lens for PPG-based heart rate detection. I explicitly select the telephoto lens using: AVCaptureDevice.default(.builtInTelephotoCamera, for: .video, position: .back) Then I attempt to lock lens switching with: device.setPrimaryConstituentDeviceSwitchingBehavior(.locked, restrictedSwitchingBehaviorConditions: []) I also lock focus, exposure, white balance, HDR, and low light boost. I stream frame data (average RGB) to a WKWebView via evaluateJavaScript() on a repeating timer. However, on iPhone 16 Pro Max, I still occasionally see: Lens switching (usually in low light or when the finger fully covers the telephoto) Or worse, the camera silently stops delivering frames (through captureOutput(_:didOutput:) ) Here’s the simplified but representative core setup: private func setupCamera() { videoDevice = AVCaptureDevice.default(.builtInTelephotoCamera, for: .video, position: .back) if #available(iOS 15.0, *), let device = videoDevice, device.activePrimaryConstituentDeviceSwitchingBehavior != .unsupported { do { try device.lockForConfiguration() device.setPrimaryConstituentDeviceSwitchingBehavior(.locked, restrictedSwitchingBehaviorConditions: []) device.unlockForConfiguration() } catch { print("Lens lock failed: \(error)") } } } func startCamera(in view: UIView) { captureSession = AVCaptureSession() guard let captureSession, let device = videoDevice else { return } do { let input = try AVCaptureDeviceInput(device: device) if captureSession.canAddInput(input) { captureSession.addInput(input) } videoOutput.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA] videoOutput.alwaysDiscardsLateVideoFrames = true videoOutput.setSampleBufferDelegate(self, queue: DispatchQueue(label: "camera.queue")) if captureSession.canAddOutput(videoOutput) { captureSession.addOutput(videoOutput) } try device.lockForConfiguration() device.focusMode = .locked device.exposureMode = .locked device.whiteBalanceMode = .locked device.automaticallyAdjustsVideoHDREnabled = false if device.isLowLightBoostSupported { device.automaticallyEnablesLowLightBoostWhenAvailable = false } // Set 60 FPS 1080p format if let format = device.formats.first(where: { CMVideoFormatDescriptionGetDimensions($0.formatDescription) == CMVideoDimensions(width: 1920, height: 1080) && $0.videoSupportedFrameRateRanges.first?.maxFrameRate ?? 0 >= 60 }) { device.activeFormat = format device.activeVideoMinFrameDuration = CMTime(value: 1, timescale: 60) device.activeVideoMaxFrameDuration = CMTime(value: 1, timescale: 60) } device.unlockForConfiguration() captureSession.startRunning() } catch { print("Camera setup error: \(error)") } startSendingColorUpdatesToWebView() } And inside the frame callback: func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return } let (r, g, b) = computeAverageColor(from: pixelBuffer) ?? (0, 0, 0) let timestampMs = Int(Date().timeIntervalSince1970 * 1000) let js = """ window.TurboNativeBridge.changeFingerAvgColorInIos(\(r), \(g), \(b), \(timestampMs)) """ DispatchQueue.main.async { self.webView?.evaluateJavaScript(js) } } My questions: Is there any way to guarantee that the system will stick to the telephoto lens under all conditions? Is there any known reason the capture session would keep running but captureOutput() would stop firing? I’d appreciate any guidance. If necessary, I can eventually put together a full project. Thanks again, Gal
Jun ’25