From 6b67904639ce07f084761af42e2df4bcb59cb5b1 Mon Sep 17 00:00:00 2001 From: Marc Rousavy Date: Sat, 10 Feb 2024 12:21:32 +0100 Subject: [PATCH 1/6] fix: Fix double configuration on device change Fixes a situation that happened on every device change (or initial mount) where the device was configured after the session, separately, instead of just all at once causing an additonal delay/flicker of the prevjew. --- package/ios/Core/CameraSession.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/package/ios/Core/CameraSession.swift b/package/ios/Core/CameraSession.swift index 92caaacc2c..6aa7e6f966 100644 --- a/package/ios/Core/CameraSession.swift +++ b/package/ios/Core/CameraSession.swift @@ -117,7 +117,11 @@ class CameraSession: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate, AVC do { // If needed, configure the AVCaptureSession (inputs, outputs) if difference.isSessionConfigurationDirty { - try self.withSessionLock { + self.session.beginConfiguration() + defer { + self.session.commitConfiguration() + } + try self.withSessionLock { // 1. Update input device if difference.inputChanged { try self.configureDevice(configuration: config) From 4ebe02d35bbc100403a377bce4bc1151c4f66ac1 Mon Sep 17 00:00:00 2001 From: Marc Rousavy Date: Tue, 13 Feb 2024 12:56:25 +0100 Subject: [PATCH 2/6] Try? --- package/ios/Core/CameraSession.swift | 133 +++++++++++---------------- 1 file changed, 52 insertions(+), 81 deletions(-) diff --git a/package/ios/Core/CameraSession.swift b/package/ios/Core/CameraSession.swift index 6aa7e6f966..a0f32ca10d 100644 --- a/package/ios/Core/CameraSession.swift +++ b/package/ios/Core/CameraSession.swift @@ -117,55 +117,61 @@ class CameraSession: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate, AVC do { // If needed, configure the AVCaptureSession (inputs, outputs) if difference.isSessionConfigurationDirty { - self.session.beginConfiguration() - defer { - self.session.commitConfiguration() - } - try self.withSessionLock { - // 1. Update input device - if difference.inputChanged { - try self.configureDevice(configuration: config) - } - // 2. Update outputs - if difference.outputsChanged { - try self.configureOutputs(configuration: config) - } - // 3. Update Video Stabilization - if difference.videoStabilizationChanged { - self.configureVideoStabilization(configuration: config) - } - // 4. Update output orientation - if difference.orientationChanged { - self.configureOrientation(configuration: config) - } + self.captureSession.beginConfiguration() + + // 1. Update input device + if difference.inputChanged { + try self.configureDevice(configuration: config) + } + // 2. Update outputs + if difference.outputsChanged { + try self.configureOutputs(configuration: config) + } + // 3. Update Video Stabilization + if difference.videoStabilizationChanged { + self.configureVideoStabilization(configuration: config) + } + // 4. Update output orientation + if difference.orientationChanged { + self.configureOrientation(configuration: config) } } + + guard let device = self.videoDeviceInput?.device else { + throw CameraError.session(.cameraNotReady) + } // If needed, configure the AVCaptureDevice (format, zoom, low-light-boost, ..) if difference.isDeviceConfigurationDirty { - try self.withDeviceLock { device in - // 4. Configure format - if difference.formatChanged { - try self.configureFormat(configuration: config, device: device) - } - // 5. After step 2. and 4., we also need to configure the PixelFormat. - // This needs to be done AFTER we updated the `format`, as this controls the supported PixelFormats. - if difference.outputsChanged || difference.formatChanged { - try self.configurePixelFormat(configuration: config) - } - // 6. Configure side-props (fps, lowLightBoost) - if difference.sidePropsChanged { - try self.configureSideProps(configuration: config, device: device) - } - // 7. Configure zoom - if difference.zoomChanged { - self.configureZoom(configuration: config, device: device) - } - // 8. Configure exposure bias - if difference.exposureChanged { - self.configureExposure(configuration: config, device: device) - } + try device.lockForConfiguration() + + // 4. Configure format + if difference.formatChanged { + try self.configureFormat(configuration: config, device: device) + } + // 5. After step 2. and 4., we also need to configure the PixelFormat. + // This needs to be done AFTER we updated the `format`, as this controls the supported PixelFormats. + if difference.outputsChanged || difference.formatChanged { + try self.configurePixelFormat(configuration: config) + } + // 6. Configure side-props (fps, lowLightBoost) + if difference.sidePropsChanged { + try self.configureSideProps(configuration: config, device: device) } + // 7. Configure zoom + if difference.zoomChanged { + self.configureZoom(configuration: config, device: device) + } + // 8. Configure exposure bias + if difference.exposureChanged { + self.configureExposure(configuration: config, device: device) + } + + device.unlockForConfiguration() + } + + if difference.isSessionConfigurationDirty { + self.captureSession.commitConfiguration() } // 9. Start or stop the session if needed @@ -173,9 +179,9 @@ class CameraSession: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate, AVC // 10. Enable or disable the Torch if needed (requires session to be running) if difference.torchChanged { - try self.withDeviceLock { device in - try self.configureTorch(configuration: config, device: device) - } + try device.lockForConfiguration() + try self.configureTorch(configuration: config, device: device) + device.unlockForConfiguration() } // Notify about Camera initialization @@ -210,41 +216,6 @@ class CameraSession: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate, AVC } } - /** - Runs the given [lambda] under an AVCaptureSession configuration lock (`beginConfiguration()`) - */ - private func withSessionLock(_ lambda: () throws -> Void) throws { - // Lock Capture Session for configuration - ReactLogger.log(level: .info, message: "Beginning CameraSession configuration...") - captureSession.beginConfiguration() - defer { - // Unlock Capture Session again and submit configuration to Hardware - self.captureSession.commitConfiguration() - ReactLogger.log(level: .info, message: "Committed CameraSession configuration!") - } - - // Call lambda - try lambda() - } - - /** - Runs the given [lambda] under an AVCaptureDevice configuration lock (`lockForConfiguration()`) - */ - private func withDeviceLock(_ lambda: (_ device: AVCaptureDevice) throws -> Void) throws { - guard let device = videoDeviceInput?.device else { - throw CameraError.session(.cameraNotReady) - } - ReactLogger.log(level: .info, message: "Beginning CaptureDevice configuration...") - try device.lockForConfiguration() - defer { - device.unlockForConfiguration() - ReactLogger.log(level: .info, message: "Committed CaptureDevice configuration!") - } - - // Call lambda with Device - try lambda(device) - } - /** Starts or stops the CaptureSession if needed (`isActive`) */ From b587fcb4f17daaa54d3e494a76e5ccac695a86e4 Mon Sep 17 00:00:00 2001 From: Marc Rousavy Date: Tue, 13 Feb 2024 13:09:52 +0100 Subject: [PATCH 3/6] Format --- package/ios/Core/CameraSession.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package/ios/Core/CameraSession.swift b/package/ios/Core/CameraSession.swift index a0f32ca10d..587efb3ca1 100644 --- a/package/ios/Core/CameraSession.swift +++ b/package/ios/Core/CameraSession.swift @@ -118,7 +118,7 @@ class CameraSession: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate, AVC // If needed, configure the AVCaptureSession (inputs, outputs) if difference.isSessionConfigurationDirty { self.captureSession.beginConfiguration() - + // 1. Update input device if difference.inputChanged { try self.configureDevice(configuration: config) @@ -136,7 +136,7 @@ class CameraSession: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate, AVC self.configureOrientation(configuration: config) } } - + guard let device = self.videoDeviceInput?.device else { throw CameraError.session(.cameraNotReady) } @@ -144,7 +144,7 @@ class CameraSession: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate, AVC // If needed, configure the AVCaptureDevice (format, zoom, low-light-boost, ..) if difference.isDeviceConfigurationDirty { try device.lockForConfiguration() - + // 4. Configure format if difference.formatChanged { try self.configureFormat(configuration: config, device: device) @@ -166,10 +166,10 @@ class CameraSession: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate, AVC if difference.exposureChanged { self.configureExposure(configuration: config, device: device) } - + device.unlockForConfiguration() } - + if difference.isSessionConfigurationDirty { self.captureSession.commitConfiguration() } From f48367d1dc71d848c20d57c542ddabb068a37759 Mon Sep 17 00:00:00 2001 From: Marc Rousavy Date: Tue, 13 Feb 2024 13:13:04 +0100 Subject: [PATCH 4/6] Update CameraSession.swift --- package/ios/Core/CameraSession.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/package/ios/Core/CameraSession.swift b/package/ios/Core/CameraSession.swift index 587efb3ca1..f707df0cb0 100644 --- a/package/ios/Core/CameraSession.swift +++ b/package/ios/Core/CameraSession.swift @@ -171,6 +171,8 @@ class CameraSession: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate, AVC } if difference.isSessionConfigurationDirty { + // We commit the session config updates AFTER the device config, + // that way we can also batch those changes into one update instead of doing two updates. self.captureSession.commitConfiguration() } From 764a39081f9d2930a909d4ade6bfef9024920be4 Mon Sep 17 00:00:00 2001 From: Marc Rousavy Date: Tue, 13 Feb 2024 13:13:51 +0100 Subject: [PATCH 5/6] Use `defer` --- package/ios/Core/CameraSession.swift | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/package/ios/Core/CameraSession.swift b/package/ios/Core/CameraSession.swift index f707df0cb0..caeac1d458 100644 --- a/package/ios/Core/CameraSession.swift +++ b/package/ios/Core/CameraSession.swift @@ -144,6 +144,9 @@ class CameraSession: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate, AVC // If needed, configure the AVCaptureDevice (format, zoom, low-light-boost, ..) if difference.isDeviceConfigurationDirty { try device.lockForConfiguration() + defer { + device.unlockForConfiguration() + } // 4. Configure format if difference.formatChanged { @@ -166,8 +169,6 @@ class CameraSession: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate, AVC if difference.exposureChanged { self.configureExposure(configuration: config, device: device) } - - device.unlockForConfiguration() } if difference.isSessionConfigurationDirty { @@ -182,8 +183,10 @@ class CameraSession: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate, AVC // 10. Enable or disable the Torch if needed (requires session to be running) if difference.torchChanged { try device.lockForConfiguration() + defer { + device.unlockForConfiguration() + } try self.configureTorch(configuration: config, device: device) - device.unlockForConfiguration() } // Notify about Camera initialization From 7f31790c65f21bd12cb4431a65ba29b0dd41f532 Mon Sep 17 00:00:00 2001 From: Marc Rousavy Date: Tue, 13 Feb 2024 13:14:43 +0100 Subject: [PATCH 6/6] Throw `.device` --- package/ios/Core/CameraSession.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/ios/Core/CameraSession.swift b/package/ios/Core/CameraSession.swift index caeac1d458..1af5dca6de 100644 --- a/package/ios/Core/CameraSession.swift +++ b/package/ios/Core/CameraSession.swift @@ -138,7 +138,7 @@ class CameraSession: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate, AVC } guard let device = self.videoDeviceInput?.device else { - throw CameraError.session(.cameraNotReady) + throw CameraError.device(.noDevice) } // If needed, configure the AVCaptureDevice (format, zoom, low-light-boost, ..)