@momo-kits/camerakit 0.161.2-beta.16 → 0.161.2-beta.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -123,34 +123,40 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
123
123
  // handled by startCamera() -> startSessionIfNeeded().
124
124
  guard self.setupResult == .notStarted else { return }
125
125
 
126
- // Configure the WHOLE session (inputs, preset, outputs) inside a single
127
- // begin/commit transaction on the session queue. The preset is set here
128
- // and never on the main queue, so the startRunning() below can no longer
129
- // observe the session mid-configuration from another thread.
130
- //
131
- // This is the root-cause fix for:
132
- // "[AVCaptureSession startRunning] startRunning may not be called between
133
- // calls to beginConfiguration and commitConfiguration".
134
- self.setupResult = self.configureSession(cameraType: cameraType,
135
- supportedBarcodeType: supportedBarcodeType)
136
-
126
+ // PHASE 1 minimal config so the preview renders ASAP. Only the video
127
+ // input + a lightweight (.high) preview preset go in this first
128
+ // transaction. The heavier work (.photo preset + photo / barcode / OCR
129
+ // outputs) is deferred to phase 2 below, AFTER the session is already
130
+ // running and the preview layer is attached. This restores the
131
+ // "camera shows up instantly" feel without weakening the crash fix.
132
+ self.setupResult = self.configureBaseSession(cameraType: cameraType)
137
133
  guard self.setupResult == .success else { return }
138
134
 
139
- // Order matches the previous behaviour: start, then observe, then torch.
140
- self.startSessionIfNeeded()
141
- self.addObservers()
142
- self.update(torchMode: self.torchMode)
143
-
144
- // Only the preview LAYER is touched on the main queue. Connecting an
135
+ // Attach the preview LAYER on the main queue BEFORE startRunning so the
136
+ // first frames render the moment the session starts. Connecting an
145
137
  // AVCaptureVideoPreviewLayer to a session from the main thread is
146
- // sanctioned by AVFoundation (see Apple's AVCam) and does NOT open a
147
- // session configuration transaction, so it cannot race startRunning().
138
+ // sanctioned by AVFoundation (see Apple's AVCam), does NOT open a
139
+ // session configuration transaction, and cannot race startRunning().
148
140
  DispatchQueue.main.async { [weak self] in
149
141
  guard let self else { return }
150
142
  self.cameraPreview.session = self.session
151
143
  self.cameraPreview.previewLayer.videoGravity = .resizeAspectFill
152
144
  self.setVideoOrientationToInterfaceOrientation()
153
145
  }
146
+
147
+ // Start running with just the preview-friendly config → fast first frame.
148
+ self.startSessionIfNeeded()
149
+
150
+ // PHASE 2 — add the heavier outputs and upgrade to the .photo preset in a
151
+ // SECOND transaction on this same serial queue, now that preview is live.
152
+ // Adding outputs to an already-running session inside begin/commit is
153
+ // legal; because startRunning() is NEVER called while configurationDepth
154
+ // > 0 (see startSessionIfNeeded), the "startRunning may not be called
155
+ // between beginConfiguration and commitConfiguration" crash stays fixed.
156
+ self.configureAdditionalOutputs(supportedBarcodeType: supportedBarcodeType)
157
+
158
+ self.addObservers()
159
+ self.update(torchMode: self.torchMode)
154
160
  }
155
161
 
156
162
  DispatchQueue.global(qos: .utility).async { [weak self] in
@@ -160,10 +166,11 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
160
166
 
161
167
  // MARK: - Private optimization methods
162
168
 
163
- /// Configures the video input, session preset and every output in ONE atomic
164
- /// transaction. Must be called on `sessionQueue`. Order is significant:
165
- /// beginConfiguration -> addInput -> set preset -> addOutputs -> commitConfiguration.
166
- private func configureSession(cameraType: CameraType, supportedBarcodeType: [CodeFormat]) -> SetupResult {
169
+ /// Phase 1 of setup: video input + a lightweight (.high) preview preset, in ONE
170
+ /// transaction. Must run on `sessionQueue`. Kept deliberately minimal so
171
+ /// `startRunning()` and therefore the first preview frame is not delayed by
172
+ /// wiring up the photo / barcode / OCR outputs (that is `configureAdditionalOutputs`).
173
+ private func configureBaseSession(cameraType: CameraType) -> SetupResult {
167
174
  assertOnSessionQueue()
168
175
  guard let videoDevice = self.getBestDevice(for: cameraType),
169
176
  let videoDeviceInput = try? AVCaptureDeviceInput(device: videoDevice) else {
@@ -173,7 +180,7 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
173
180
  beginConfiguration()
174
181
  defer { commitConfiguration() }
175
182
 
176
- // 1. Video input
183
+ // Video input
177
184
  guard session.canAddInput(videoDeviceInput) else {
178
185
  return .sessionConfigurationFailed
179
186
  }
@@ -181,15 +188,33 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
181
188
  self.videoDeviceInput = videoDeviceInput
182
189
  self.resetZoom(forDevice: videoDevice)
183
190
 
184
- // 2. Preset set inside the transaction with the device input already
185
- // present, so `canSetSessionPreset` reflects the real device. `.photo` is
186
- // supported by every camera device; if it somehow is not, we keep whatever
187
- // preset the session defaults to rather than crashing.
191
+ // Lightweight preset for the fastest possible first frame. Upgraded to
192
+ // `.photo` in configureAdditionalOutputs() once the preview is live.
193
+ if session.canSetSessionPreset(.high) {
194
+ session.sessionPreset = .high
195
+ }
196
+
197
+ return .success
198
+ }
199
+
200
+ /// Phase 2 of setup: the .photo preset + photo / barcode / OCR outputs, in ONE
201
+ /// transaction on `sessionQueue`. Runs AFTER the session is already running and
202
+ /// the preview is attached, so none of this work delays the first frame. Adding
203
+ /// outputs to a running session inside begin/commit is legal; the crash fix is
204
+ /// preserved because startRunning() is never called while a transaction is open.
205
+ private func configureAdditionalOutputs(supportedBarcodeType: [CodeFormat]) {
206
+ assertOnSessionQueue()
207
+ beginConfiguration()
208
+ defer { commitConfiguration() }
209
+
210
+ // Upgrade to the full still-capture preset now that preview is rendering.
211
+ // `.photo` is supported by every camera device; if it somehow is not, we
212
+ // keep the `.high` preset from phase 1 rather than crashing.
188
213
  if session.canSetSessionPreset(.photo) {
189
214
  session.sessionPreset = .photo
190
215
  }
191
216
 
192
- // 3. Photo output
217
+ // Photo output
193
218
  if #available(iOS 13.0, *) {
194
219
  if let maxPhotoQualityPrioritization = maxPhotoQualityPrioritization {
195
220
  photoOutput.maxPhotoQualityPrioritization = maxPhotoQualityPrioritization.avQualityPrioritization
@@ -204,7 +229,7 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
204
229
  }
205
230
  }
206
231
 
207
- // 4. Metadata output for barcode scanning
232
+ // Metadata output for barcode scanning
208
233
  if self.session.canAddOutput(metadataOutput) {
209
234
  self.session.addOutput(metadataOutput)
210
235
  metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
@@ -217,12 +242,10 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
217
242
  metadataOutput.metadataObjectTypes = filteredTypes
218
243
  }
219
244
 
220
- // 5. Video data output for text / MRZ detection
245
+ // Video data output for text / MRZ detection
221
246
  if textRequest != nil && self.session.canAddOutput(self.videoDataOutput) {
222
247
  self.session.addOutput(self.videoDataOutput)
223
248
  }
224
-
225
- return .success
226
249
  }
227
250
 
228
251
  // MARK: - Pause / Resume non-essential outputs
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/camerakit",
3
- "version": "0.161.2-beta.16",
3
+ "version": "0.161.2-beta.25",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/teslamotors/react-native-camera-kit.git"