expo-camera 16.0.15 → 16.0.16
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.
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,10 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 16.0.16 — 2025-02-10
|
|
14
|
+
|
|
15
|
+
_This version does not introduce any user-facing changes._
|
|
16
|
+
|
|
13
17
|
## 16.0.15 — 2025-02-06
|
|
14
18
|
|
|
15
19
|
_This version does not introduce any user-facing changes._
|
|
@@ -36,6 +40,8 @@ _This version does not introduce any user-facing changes._
|
|
|
36
40
|
- [Android] Fix an issue where the camera image is pixelated when using the gl integration. ([#34174](https://github.com/expo/expo/pull/34174) by [@alanjhughes](https://github.com/alanjhughes))
|
|
37
41
|
- [Android] Fix setting the camera preview provider. ([#34302](https://github.com/expo/expo/pull/34302) by [@alanjhughes](https://github.com/alanjhughes))
|
|
38
42
|
- [iOS] Fix initial roation when used with `react-native-screens`. ([#34721](https://github.com/expo/expo/pull/34721) by [@alanjhughes](https://github.com/alanjhughes))
|
|
43
|
+
- [iOS] Fix performance regression. ([#34750](https://github.com/expo/expo/pull/34750) by [@alanjhughes](https://github.com/alanjhughes))
|
|
44
|
+
- [Android] Attempt to fix `setLinearZoom` incompatability with some devices. ([#34757](https://github.com/expo/expo/pull/34757) by [@alanjhughes](https://github.com/alanjhughes))
|
|
39
45
|
|
|
40
46
|
## 16.0.10 — 2024-12-16
|
|
41
47
|
|
package/android/build.gradle
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
apply plugin: 'com.android.library'
|
|
2
2
|
|
|
3
3
|
group = 'host.exp.exponent'
|
|
4
|
-
version = '16.0.
|
|
4
|
+
version = '16.0.16'
|
|
5
5
|
|
|
6
6
|
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
|
7
7
|
apply from: expoModulesCorePlugin
|
|
@@ -14,7 +14,7 @@ android {
|
|
|
14
14
|
namespace "expo.modules.camera"
|
|
15
15
|
defaultConfig {
|
|
16
16
|
versionCode 32
|
|
17
|
-
versionName "16.0.
|
|
17
|
+
versionName "16.0.16"
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -81,6 +81,8 @@ import kotlinx.coroutines.Dispatchers
|
|
|
81
81
|
import kotlinx.coroutines.cancel
|
|
82
82
|
import kotlinx.coroutines.launch
|
|
83
83
|
import java.io.File
|
|
84
|
+
import java.lang.Float.max
|
|
85
|
+
import java.lang.Float.min
|
|
84
86
|
import kotlin.math.roundToInt
|
|
85
87
|
import kotlin.properties.Delegates
|
|
86
88
|
|
|
@@ -150,7 +152,7 @@ class ExpoCameraView(
|
|
|
150
152
|
var zoom: Float = 0f
|
|
151
153
|
set(value) {
|
|
152
154
|
field = value
|
|
153
|
-
|
|
155
|
+
setCameraZoom(value)
|
|
154
156
|
}
|
|
155
157
|
|
|
156
158
|
var autoFocus: FocusMode = FocusMode.OFF
|
|
@@ -431,7 +433,7 @@ class ExpoCameraView(
|
|
|
431
433
|
observeCameraState(it.cameraInfo)
|
|
432
434
|
}
|
|
433
435
|
// Set the previous zoom level after recreating the camera
|
|
434
|
-
|
|
436
|
+
setCameraZoom(zoom)
|
|
435
437
|
this.cameraProvider = cameraProvider
|
|
436
438
|
} catch (e: Exception) {
|
|
437
439
|
onMountError(
|
|
@@ -544,6 +546,12 @@ class ExpoCameraView(
|
|
|
544
546
|
}
|
|
545
547
|
}
|
|
546
548
|
|
|
549
|
+
private fun setCameraZoom(value: Float) {
|
|
550
|
+
val maxZoomRatio = camera?.cameraInfo?.zoomState?.value?.maxZoomRatio ?: 1f
|
|
551
|
+
val targetZoomRatio = max(1f, min(maxZoomRatio, value.coerceIn(0f, 1f) * maxZoomRatio))
|
|
552
|
+
camera?.cameraControl?.setZoomRatio(targetZoomRatio)
|
|
553
|
+
}
|
|
554
|
+
|
|
547
555
|
private fun observeCameraState(cameraInfo: CameraInfo) {
|
|
548
556
|
cameraInfo.cameraState.observe(currentActivity) {
|
|
549
557
|
when (it.type) {
|
|
@@ -76,27 +76,48 @@ public final class CameraViewModule: Module, ScannerResultHandler {
|
|
|
76
76
|
if let type, view.presetCamera != type.toPosition() {
|
|
77
77
|
view.presetCamera = type.toPosition()
|
|
78
78
|
}
|
|
79
|
+
// the prop has been removed, reset to default
|
|
80
|
+
if type == nil && view.presetCamera != .back {
|
|
81
|
+
view.presetCamera = .back
|
|
82
|
+
}
|
|
79
83
|
}
|
|
80
84
|
|
|
81
85
|
Prop("flashMode") { (view, flashMode: FlashMode?) in
|
|
82
86
|
if let flashMode, view.flashMode != flashMode {
|
|
83
87
|
view.flashMode = flashMode
|
|
84
88
|
}
|
|
89
|
+
if flashMode == nil && view.flashMode != .auto {
|
|
90
|
+
view.flashMode = .auto
|
|
91
|
+
}
|
|
85
92
|
}
|
|
86
93
|
|
|
87
94
|
Prop("enableTorch") { (view, enabled: Bool?) in
|
|
88
|
-
view.torchEnabled
|
|
95
|
+
if let enabled, view.torchEnabled != enabled {
|
|
96
|
+
view.torchEnabled = enabled
|
|
97
|
+
return
|
|
98
|
+
}
|
|
99
|
+
if enabled == nil && view.torchEnabled {
|
|
100
|
+
view.torchEnabled = false
|
|
101
|
+
}
|
|
89
102
|
}
|
|
90
103
|
|
|
91
104
|
Prop("pictureSize") { (view, pictureSize: PictureSize?) in
|
|
92
105
|
if let pictureSize, view.pictureSize != pictureSize {
|
|
93
106
|
view.pictureSize = pictureSize
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
if pictureSize == nil && view.pictureSize != .high {
|
|
110
|
+
view.pictureSize = .high
|
|
94
111
|
}
|
|
95
112
|
}
|
|
96
113
|
|
|
97
114
|
Prop("zoom") { (view, zoom: Double?) in
|
|
98
115
|
if let zoom, fabs(view.zoom - zoom) > Double.ulpOfOne {
|
|
99
116
|
view.zoom = zoom
|
|
117
|
+
return
|
|
118
|
+
}
|
|
119
|
+
if zoom == nil && view.zoom != 0 {
|
|
120
|
+
view.zoom = 0
|
|
100
121
|
}
|
|
101
122
|
}
|
|
102
123
|
|
|
@@ -104,11 +125,18 @@ public final class CameraViewModule: Module, ScannerResultHandler {
|
|
|
104
125
|
if let mode, view.mode != mode {
|
|
105
126
|
view.mode = mode
|
|
106
127
|
}
|
|
128
|
+
if mode == nil && view.mode != .picture {
|
|
129
|
+
view.mode = .picture
|
|
130
|
+
}
|
|
107
131
|
}
|
|
108
132
|
|
|
109
133
|
Prop("barcodeScannerEnabled") { (view, scanBarcodes: Bool?) in
|
|
110
134
|
if let scanBarcodes, view.isScanningBarcodes != scanBarcodes {
|
|
111
135
|
view.isScanningBarcodes = scanBarcodes
|
|
136
|
+
return
|
|
137
|
+
}
|
|
138
|
+
if scanBarcodes == nil && view.isScanningBarcodes != false {
|
|
139
|
+
view.isScanningBarcodes = false
|
|
112
140
|
}
|
|
113
141
|
}
|
|
114
142
|
|
|
@@ -119,56 +147,71 @@ public final class CameraViewModule: Module, ScannerResultHandler {
|
|
|
119
147
|
}
|
|
120
148
|
|
|
121
149
|
Prop("mute") { (view, muted: Bool?) in
|
|
122
|
-
view.isMuted
|
|
150
|
+
if let muted, view.isMuted != muted {
|
|
151
|
+
view.isMuted = muted
|
|
152
|
+
return
|
|
153
|
+
}
|
|
154
|
+
if muted == nil && view.isMuted != false {
|
|
155
|
+
view.isMuted = false
|
|
156
|
+
}
|
|
123
157
|
}
|
|
124
158
|
|
|
125
159
|
Prop("animateShutter") { (view, animate: Bool?) in
|
|
160
|
+
// Does not call anything that immediately causes any configuration changes
|
|
161
|
+
// so it's fine to just set it
|
|
126
162
|
view.animateShutter = animate ?? true
|
|
127
163
|
}
|
|
128
164
|
|
|
129
165
|
Prop("videoQuality") { (view, quality: VideoQuality?) in
|
|
130
|
-
view.videoQuality
|
|
166
|
+
if let quality, view.videoQuality != quality {
|
|
167
|
+
view.videoQuality = quality
|
|
168
|
+
return
|
|
169
|
+
}
|
|
170
|
+
if quality == nil && view.videoQuality != .video1080p {
|
|
171
|
+
view.videoQuality = .video1080p
|
|
172
|
+
}
|
|
131
173
|
}
|
|
132
174
|
|
|
133
175
|
Prop("autoFocus") { (view, focusMode: FocusMode?) in
|
|
134
|
-
view.autoFocus
|
|
176
|
+
if let focusMode, view.autoFocus != focusMode.toAVCaptureFocusMode() {
|
|
177
|
+
view.autoFocus = focusMode.toAVCaptureFocusMode()
|
|
178
|
+
return
|
|
179
|
+
}
|
|
180
|
+
if focusMode == nil && view.autoFocus != .continuousAutoFocus {
|
|
181
|
+
view.autoFocus = .continuousAutoFocus
|
|
182
|
+
}
|
|
135
183
|
}
|
|
136
184
|
|
|
137
185
|
Prop("responsiveOrientationWhenOrientationLocked") { (view, responsiveOrientation: Bool?) in
|
|
138
186
|
if let responsiveOrientation, view.responsiveWhenOrientationLocked != responsiveOrientation {
|
|
139
187
|
view.responsiveWhenOrientationLocked = responsiveOrientation
|
|
188
|
+
return
|
|
189
|
+
}
|
|
190
|
+
if responsiveOrientation == nil && view.responsiveWhenOrientationLocked != false {
|
|
191
|
+
view.responsiveWhenOrientationLocked = false
|
|
140
192
|
}
|
|
141
193
|
}
|
|
142
194
|
|
|
143
195
|
Prop("mirror") { (view, mirror: Bool?) in
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
view.mirror = false
|
|
196
|
+
// Does not call anything that immediately causes any configuration changes
|
|
197
|
+
// so it's fine to just set it
|
|
198
|
+
view.mirror = mirror ?? false
|
|
149
199
|
}
|
|
150
200
|
|
|
151
201
|
Prop("active") { (view, active: Bool?) in
|
|
152
|
-
if let active {
|
|
202
|
+
if let active, view.active != active {
|
|
153
203
|
view.active = active
|
|
154
204
|
return
|
|
155
205
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
Prop("videoBitrate") { (view, bitrate: Int?) in
|
|
159
|
-
if let bitrate {
|
|
160
|
-
view.videoBitrate = bitrate
|
|
161
|
-
return
|
|
162
|
-
}
|
|
163
|
-
if view.videoBitrate != nil {
|
|
164
|
-
view.videoBitrate = nil
|
|
206
|
+
if active == nil && view.active != true {
|
|
207
|
+
view.active = true
|
|
165
208
|
}
|
|
166
209
|
}
|
|
167
210
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
211
|
+
Prop("videoBitrate") { (view, bitrate: Int?) in
|
|
212
|
+
// Does not call anything that immediately causes any configuration changes
|
|
213
|
+
// so it's fine to just set it
|
|
214
|
+
view.videoBitrate = bitrate
|
|
172
215
|
}
|
|
173
216
|
|
|
174
217
|
AsyncFunction("resumePreview") { view in
|
|
@@ -108,9 +108,6 @@ actor BarcodeScanner: NSObject, BarcodeScanningResponseHandler {
|
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
private func addOutputs() async {
|
|
111
|
-
session.beginConfiguration()
|
|
112
|
-
defer { session.commitConfiguration() }
|
|
113
|
-
|
|
114
111
|
delegate = MetaDataDelegate(
|
|
115
112
|
settings: settings,
|
|
116
113
|
previewLayer: previewLayer,
|
|
@@ -118,6 +115,7 @@ actor BarcodeScanner: NSObject, BarcodeScanningResponseHandler {
|
|
|
118
115
|
zxingEnabled: zxingEnabled,
|
|
119
116
|
metadataResultHandler: self)
|
|
120
117
|
|
|
118
|
+
session.beginConfiguration()
|
|
121
119
|
if metadataOutput == nil {
|
|
122
120
|
let output = AVCaptureMetadataOutput()
|
|
123
121
|
output.setMetadataObjectsDelegate(delegate, queue: sessionQueue)
|
|
@@ -137,6 +135,7 @@ actor BarcodeScanner: NSObject, BarcodeScanningResponseHandler {
|
|
|
137
135
|
videoDataOutput = output
|
|
138
136
|
}
|
|
139
137
|
}
|
|
138
|
+
session.commitConfiguration()
|
|
140
139
|
}
|
|
141
140
|
|
|
142
141
|
private func removeOutputs() async {
|
|
@@ -26,7 +26,6 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
|
|
|
26
26
|
mm.gyroUpdateInterval = 0.2
|
|
27
27
|
return mm
|
|
28
28
|
}()
|
|
29
|
-
private var cameraShouldInit = true
|
|
30
29
|
private var isSessionPaused = false
|
|
31
30
|
|
|
32
31
|
// MARK: Property Observers
|
|
@@ -39,8 +38,8 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
|
|
|
39
38
|
|
|
40
39
|
var videoQuality: VideoQuality = .video1080p {
|
|
41
40
|
didSet {
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
sessionQueue.async {
|
|
42
|
+
self.updateSessionPreset(preset: self.videoQuality.toPreset())
|
|
44
43
|
}
|
|
45
44
|
}
|
|
46
45
|
}
|
|
@@ -57,7 +56,9 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
|
|
|
57
56
|
|
|
58
57
|
var presetCamera = AVCaptureDevice.Position.back {
|
|
59
58
|
didSet {
|
|
60
|
-
|
|
59
|
+
sessionQueue.async {
|
|
60
|
+
self.updateDevice()
|
|
61
|
+
}
|
|
61
62
|
}
|
|
62
63
|
}
|
|
63
64
|
|
|
@@ -77,31 +78,31 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
|
|
|
77
78
|
|
|
78
79
|
var pictureSize = PictureSize.high {
|
|
79
80
|
didSet {
|
|
80
|
-
|
|
81
|
-
await updatePictureSize()
|
|
82
|
-
}
|
|
81
|
+
updatePictureSize()
|
|
83
82
|
}
|
|
84
83
|
}
|
|
85
84
|
|
|
86
85
|
var mode = CameraMode.picture {
|
|
87
86
|
didSet {
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
sessionQueue.async {
|
|
88
|
+
self.setCameraMode()
|
|
90
89
|
}
|
|
91
90
|
}
|
|
92
91
|
}
|
|
93
92
|
|
|
94
93
|
var isMuted = false {
|
|
95
94
|
didSet {
|
|
96
|
-
|
|
97
|
-
|
|
95
|
+
sessionQueue.async {
|
|
96
|
+
self.updateSessionAudioIsMuted()
|
|
98
97
|
}
|
|
99
98
|
}
|
|
100
99
|
}
|
|
101
100
|
|
|
102
101
|
var active = true {
|
|
103
102
|
didSet {
|
|
104
|
-
|
|
103
|
+
sessionQueue.async {
|
|
104
|
+
self.updateCameraIsActive()
|
|
105
|
+
}
|
|
105
106
|
}
|
|
106
107
|
}
|
|
107
108
|
|
|
@@ -154,6 +155,7 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
|
|
|
154
155
|
name: UIDevice.orientationDidChangeNotification,
|
|
155
156
|
object: nil)
|
|
156
157
|
lifecycleManager?.register(self)
|
|
158
|
+
initializeCaptureSessionInput()
|
|
157
159
|
}
|
|
158
160
|
|
|
159
161
|
private func setupPreview() {
|
|
@@ -161,44 +163,51 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
|
|
|
161
163
|
previewLayer.needsDisplayOnBoundsChange = true
|
|
162
164
|
}
|
|
163
165
|
|
|
164
|
-
func
|
|
165
|
-
guard
|
|
166
|
+
private func updateDevice() {
|
|
167
|
+
guard let device = ExpoCameraUtils.device(with: .video, preferring: presetCamera) else {
|
|
166
168
|
return
|
|
167
169
|
}
|
|
168
|
-
cameraShouldInit = false
|
|
169
|
-
await initializeCaptureSessionInput()
|
|
170
|
-
}
|
|
171
170
|
|
|
172
|
-
|
|
173
|
-
|
|
171
|
+
session.beginConfiguration()
|
|
172
|
+
defer { session.commitConfiguration() }
|
|
173
|
+
if let captureDeviceInput {
|
|
174
|
+
session.removeInput(captureDeviceInput)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
do {
|
|
178
|
+
let deviceInput = try AVCaptureDeviceInput(device: device)
|
|
179
|
+
if session.canAddInput(deviceInput) {
|
|
180
|
+
session.addInput(deviceInput)
|
|
181
|
+
captureDeviceInput = deviceInput
|
|
182
|
+
updateZoom()
|
|
183
|
+
}
|
|
184
|
+
} catch {
|
|
185
|
+
onMountError(["message": "Camera could not be started - \(error.localizedDescription)"])
|
|
186
|
+
}
|
|
174
187
|
}
|
|
175
188
|
|
|
176
189
|
public func onAppForegrounded() {
|
|
177
190
|
if !session.isRunning && isSessionPaused {
|
|
178
191
|
isSessionPaused = false
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
self.enableTorch()
|
|
182
|
-
}
|
|
192
|
+
session.startRunning()
|
|
193
|
+
enableTorch()
|
|
183
194
|
}
|
|
184
195
|
}
|
|
185
196
|
|
|
186
197
|
public func onAppBackgrounded() {
|
|
187
198
|
if session.isRunning && !isSessionPaused {
|
|
188
199
|
isSessionPaused = true
|
|
189
|
-
|
|
190
|
-
self.session.stopRunning()
|
|
191
|
-
}
|
|
200
|
+
session.stopRunning()
|
|
192
201
|
}
|
|
193
202
|
}
|
|
194
203
|
|
|
195
|
-
private func updatePictureSize()
|
|
204
|
+
private func updatePictureSize() {
|
|
196
205
|
#if !targetEnvironment(simulator)
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
206
|
+
sessionQueue.async {
|
|
207
|
+
let preset = self.pictureSize.toCapturePreset()
|
|
208
|
+
if self.session.canSetSessionPreset(preset) {
|
|
209
|
+
self.session.sessionPreset = preset
|
|
210
|
+
}
|
|
202
211
|
}
|
|
203
212
|
#endif
|
|
204
213
|
}
|
|
@@ -236,18 +245,18 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
|
|
|
236
245
|
device.unlockForConfiguration()
|
|
237
246
|
}
|
|
238
247
|
|
|
239
|
-
private func setCameraMode()
|
|
248
|
+
private func setCameraMode() {
|
|
240
249
|
if mode == .video {
|
|
241
250
|
if videoFileOutput == nil {
|
|
242
|
-
|
|
251
|
+
setupMovieFileCapture()
|
|
243
252
|
}
|
|
244
|
-
|
|
253
|
+
updateSessionAudioIsMuted()
|
|
245
254
|
} else {
|
|
246
|
-
|
|
255
|
+
cleanupMovieFileCapture()
|
|
247
256
|
}
|
|
248
257
|
}
|
|
249
258
|
|
|
250
|
-
private func startSession()
|
|
259
|
+
private func startSession() {
|
|
251
260
|
#if targetEnvironment(simulator)
|
|
252
261
|
return
|
|
253
262
|
#else
|
|
@@ -262,17 +271,19 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
|
|
|
262
271
|
|
|
263
272
|
let photoOutput = AVCapturePhotoOutput()
|
|
264
273
|
photoOutput.isLivePhotoCaptureEnabled = false
|
|
274
|
+
session.beginConfiguration()
|
|
265
275
|
if session.canAddOutput(photoOutput) {
|
|
266
276
|
session.addOutput(photoOutput)
|
|
267
277
|
self.photoOutput = photoOutput
|
|
268
278
|
}
|
|
269
279
|
|
|
270
280
|
session.sessionPreset = mode == .video ? pictureSize.toCapturePreset() : .photo
|
|
271
|
-
addErrorNotification()
|
|
272
|
-
await changePreviewOrientation()
|
|
273
|
-
|
|
274
|
-
await barcodeScanner?.maybeStartBarcodeScanning()
|
|
275
281
|
session.commitConfiguration()
|
|
282
|
+
addErrorNotification()
|
|
283
|
+
changePreviewOrientation()
|
|
284
|
+
Task.detached(priority: .userInitiated, operation: {
|
|
285
|
+
await self.barcodeScanner?.maybeStartBarcodeScanning()
|
|
286
|
+
})
|
|
276
287
|
updateCameraIsActive()
|
|
277
288
|
onCameraReady()
|
|
278
289
|
enableTorch()
|
|
@@ -303,7 +314,9 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
|
|
|
303
314
|
if !session.isRunning {
|
|
304
315
|
session.startRunning()
|
|
305
316
|
}
|
|
306
|
-
|
|
317
|
+
sessionQueue.async {
|
|
318
|
+
self.updateSessionAudioIsMuted()
|
|
319
|
+
}
|
|
307
320
|
onCameraReady()
|
|
308
321
|
}
|
|
309
322
|
}
|
|
@@ -593,14 +606,14 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
|
|
|
593
606
|
self.videoCodecType = codecType
|
|
594
607
|
} else {
|
|
595
608
|
promise.reject(CameraRecordingException(options.codec?.rawValue))
|
|
596
|
-
|
|
609
|
+
cleanupMovieFileCapture()
|
|
597
610
|
videoRecordedPromise = nil
|
|
598
611
|
isValidVideoOptions = false
|
|
599
612
|
}
|
|
600
613
|
}
|
|
601
614
|
}
|
|
602
615
|
|
|
603
|
-
func updateSessionAudioIsMuted()
|
|
616
|
+
func updateSessionAudioIsMuted() {
|
|
604
617
|
session.beginConfiguration()
|
|
605
618
|
defer { session.commitConfiguration() }
|
|
606
619
|
|
|
@@ -629,21 +642,17 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
|
|
|
629
642
|
}
|
|
630
643
|
}
|
|
631
644
|
|
|
632
|
-
func setupMovieFileCapture()
|
|
645
|
+
func setupMovieFileCapture() {
|
|
633
646
|
let output = AVCaptureMovieFileOutput()
|
|
634
647
|
if session.canAddOutput(output) {
|
|
635
|
-
session.beginConfiguration()
|
|
636
|
-
defer { session.commitConfiguration() }
|
|
637
648
|
session.addOutput(output)
|
|
638
649
|
videoFileOutput = output
|
|
639
650
|
}
|
|
640
651
|
}
|
|
641
652
|
|
|
642
|
-
func cleanupMovieFileCapture()
|
|
653
|
+
func cleanupMovieFileCapture() {
|
|
643
654
|
if let videoFileOutput {
|
|
644
655
|
if session.outputs.contains(videoFileOutput) {
|
|
645
|
-
session.beginConfiguration()
|
|
646
|
-
defer { session.commitConfiguration() }
|
|
647
656
|
session.removeOutput(videoFileOutput)
|
|
648
657
|
self.videoFileOutput = nil
|
|
649
658
|
}
|
|
@@ -659,8 +668,8 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
|
|
|
659
668
|
|
|
660
669
|
public override func removeFromSuperview() {
|
|
661
670
|
super.removeFromSuperview()
|
|
662
|
-
|
|
663
|
-
|
|
671
|
+
sessionQueue.async {
|
|
672
|
+
self.stopSession()
|
|
664
673
|
}
|
|
665
674
|
lifecycleManager?.unregisterAppLifecycleListener(self)
|
|
666
675
|
UIDevice.current.endGeneratingDeviceOrientationNotifications()
|
|
@@ -704,15 +713,11 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
|
|
|
704
713
|
videoCodecType = nil
|
|
705
714
|
}
|
|
706
715
|
|
|
707
|
-
func setPresetCamera(presetCamera: AVCaptureDevice.Position) {
|
|
708
|
-
self.presetCamera = presetCamera
|
|
709
|
-
}
|
|
710
|
-
|
|
711
716
|
func stopRecording() {
|
|
712
717
|
videoFileOutput?.stopRecording()
|
|
713
718
|
}
|
|
714
719
|
|
|
715
|
-
func updateSessionPreset(preset: AVCaptureSession.Preset)
|
|
720
|
+
func updateSessionPreset(preset: AVCaptureSession.Preset) {
|
|
716
721
|
#if !targetEnvironment(simulator)
|
|
717
722
|
if session.canSetSessionPreset(preset) {
|
|
718
723
|
if session.sessionPreset != preset {
|
|
@@ -720,36 +725,25 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
|
|
|
720
725
|
defer { session.commitConfiguration() }
|
|
721
726
|
session.sessionPreset = preset
|
|
722
727
|
}
|
|
728
|
+
} else {
|
|
729
|
+
// The selected preset cannot be used on the current device so we fall back to the highest available.
|
|
730
|
+
if session.sessionPreset != .high {
|
|
731
|
+
session.beginConfiguration()
|
|
732
|
+
defer { session.commitConfiguration() }
|
|
733
|
+
session.sessionPreset = .high
|
|
734
|
+
}
|
|
723
735
|
}
|
|
724
736
|
#endif
|
|
725
737
|
}
|
|
726
738
|
|
|
727
|
-
func initializeCaptureSessionInput()
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
return
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
if let captureDeviceInput {
|
|
735
|
-
session.removeInput(captureDeviceInput)
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
do {
|
|
739
|
-
let deviceInput = try AVCaptureDeviceInput(device: device)
|
|
740
|
-
|
|
741
|
-
if session.canAddInput(deviceInput) {
|
|
742
|
-
session.addInput(deviceInput)
|
|
743
|
-
captureDeviceInput = deviceInput
|
|
744
|
-
updateZoom()
|
|
745
|
-
}
|
|
746
|
-
} catch {
|
|
747
|
-
onMountError(["message": "Camera could not be started - \(error.localizedDescription)"])
|
|
739
|
+
func initializeCaptureSessionInput() {
|
|
740
|
+
sessionQueue.async {
|
|
741
|
+
self.updateDevice()
|
|
742
|
+
self.startSession()
|
|
748
743
|
}
|
|
749
|
-
await startSession()
|
|
750
744
|
}
|
|
751
745
|
|
|
752
|
-
private func stopSession()
|
|
746
|
+
private func stopSession() {
|
|
753
747
|
#if targetEnvironment(simulator)
|
|
754
748
|
return
|
|
755
749
|
#else
|
|
@@ -761,7 +755,9 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
|
|
|
761
755
|
for output in session.outputs {
|
|
762
756
|
session.removeOutput(output)
|
|
763
757
|
}
|
|
764
|
-
|
|
758
|
+
Task {
|
|
759
|
+
await barcodeScanner?.stopBarcodeScanning()
|
|
760
|
+
}
|
|
765
761
|
session.commitConfiguration()
|
|
766
762
|
|
|
767
763
|
motionManager.stopAccelerometerUpdates()
|
|
@@ -785,13 +781,14 @@ public class CameraView: ExpoView, EXAppLifecycleListener,
|
|
|
785
781
|
}
|
|
786
782
|
}
|
|
787
783
|
|
|
788
|
-
|
|
789
|
-
func changePreviewOrientation() async {
|
|
784
|
+
func changePreviewOrientation() {
|
|
790
785
|
// We shouldn't access the device orientation anywhere but on the main thread
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
786
|
+
Task { @MainActor in
|
|
787
|
+
let videoOrientation = ExpoCameraUtils.videoOrientation(for: deviceOrientation)
|
|
788
|
+
if (previewLayer.connection?.isVideoOrientationSupported) == true {
|
|
789
|
+
physicalOrientation = ExpoCameraUtils.physicalOrientation(for: deviceOrientation)
|
|
790
|
+
previewLayer.connection?.videoOrientation = videoOrientation
|
|
791
|
+
}
|
|
795
792
|
}
|
|
796
793
|
}
|
|
797
794
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-camera",
|
|
3
|
-
"version": "16.0.
|
|
3
|
+
"version": "16.0.16",
|
|
4
4
|
"description": "A React component that renders a preview for the device's either front or back camera. Camera's parameters like zoom, auto focus, white balance and flash mode are adjustable. With expo-camera, one can also take photos and record videos that are saved to the app's cache. Morever, the component is also capable of detecting faces and bar codes appearing on the preview.",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -50,5 +50,5 @@
|
|
|
50
50
|
"optional": true
|
|
51
51
|
}
|
|
52
52
|
},
|
|
53
|
-
"gitHead": "
|
|
53
|
+
"gitHead": "81941fa03383e748ba1b6345d9ca0d048bb5c4d1"
|
|
54
54
|
}
|