| 
									
										
										
										
											2023-10-13 18:33:20 +02:00
										 |  |  | // | 
					
						
							|  |  |  | //  CameraSession+Focus.swift | 
					
						
							|  |  |  | //  VisionCamera | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | //  Created by Marc Rousavy on 11.10.23. | 
					
						
							|  |  |  | //  Copyright © 2023 mrousavy. All rights reserved. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import AVFoundation | 
					
						
							|  |  |  | import Foundation | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | extension CameraSession { | 
					
						
							|  |  |  |   /**
 | 
					
						
							|  |  |  |    Focuses the Camera to the specified point. The point must be in the Camera coordinate system, so {0...1} on both axis. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   func focus(point: CGPoint) throws { | 
					
						
							|  |  |  |     guard let device = videoDeviceInput?.device else { | 
					
						
							|  |  |  |       throw CameraError.session(SessionError.cameraNotReady) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if !device.isFocusPointOfInterestSupported { | 
					
						
							|  |  |  |       throw CameraError.device(DeviceError.focusNotSupported) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-27 14:43:56 +01:00
										 |  |  |     ReactLogger.log(level: .info, message: "Focusing (\(point.x), \(point.y))...") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-13 18:33:20 +02:00
										 |  |  |     do { | 
					
						
							|  |  |  |       try device.lockForConfiguration() | 
					
						
							|  |  |  |       defer { | 
					
						
							|  |  |  |         device.unlockForConfiguration() | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Set Focus | 
					
						
							|  |  |  |       if device.isFocusPointOfInterestSupported { | 
					
						
							|  |  |  |         device.focusPointOfInterest = point | 
					
						
							|  |  |  |         device.focusMode = .autoFocus | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Set Exposure | 
					
						
							|  |  |  |       if device.isExposurePointOfInterestSupported { | 
					
						
							|  |  |  |         device.exposurePointOfInterest = point | 
					
						
							|  |  |  |         device.exposureMode = .autoExpose | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Remove any existing listeners | 
					
						
							|  |  |  |       NotificationCenter.default.removeObserver(self, | 
					
						
							|  |  |  |                                                 name: NSNotification.Name.AVCaptureDeviceSubjectAreaDidChange, | 
					
						
							|  |  |  |                                                 object: nil) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // Listen for focus completion | 
					
						
							|  |  |  |       device.isSubjectAreaChangeMonitoringEnabled = true | 
					
						
							|  |  |  |       NotificationCenter.default.addObserver(self, | 
					
						
							|  |  |  |                                              selector: #selector(subjectAreaDidChange), | 
					
						
							|  |  |  |                                              name: NSNotification.Name.AVCaptureDeviceSubjectAreaDidChange, | 
					
						
							|  |  |  |                                              object: nil) | 
					
						
							|  |  |  |     } catch { | 
					
						
							|  |  |  |       throw CameraError.device(DeviceError.configureError) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   @objc | 
					
						
							|  |  |  |   func subjectAreaDidChange(notification _: NSNotification) { | 
					
						
							|  |  |  |     guard let device = videoDeviceInput?.device else { | 
					
						
							|  |  |  |       return | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     try? device.lockForConfiguration() | 
					
						
							|  |  |  |     defer { | 
					
						
							|  |  |  |       device.unlockForConfiguration() | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Reset Focus to continuous/auto | 
					
						
							|  |  |  |     if device.isFocusPointOfInterestSupported { | 
					
						
							|  |  |  |       device.focusMode = .continuousAutoFocus | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Reset Exposure to continuous/auto | 
					
						
							|  |  |  |     if device.isExposurePointOfInterestSupported { | 
					
						
							|  |  |  |       device.exposureMode = .continuousAutoExposure | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // Disable listeners | 
					
						
							|  |  |  |     device.isSubjectAreaChangeMonitoringEnabled = false | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |