Skip to content

Commit d66363f

Browse files
committed
chore: back camera support
1 parent 16a4ded commit d66363f

File tree

7 files changed

+34
-13
lines changed

7 files changed

+34
-13
lines changed

HostApp/HostApp/Views/ExampleLivenessView.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ struct ExampleLivenessView: View {
2323
FaceLivenessDetectorView(
2424
sessionID: viewModel.sessionID,
2525
region: "us-east-1",
26+
cameraPosition: .front,
2627
isPresented: Binding(
2728
get: { viewModel.presentationState == .liveness },
2829
set: { _ in }

Sources/FaceLiveness/AV/LivenessCaptureDevice.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,8 @@ struct LivenessCaptureDevice {
3737
}
3838
}
3939
}
40+
41+
public enum LivenessCaptureDevicePosition {
42+
case front
43+
case back
44+
}

Sources/FaceLiveness/Views/GetReadyPage/CameraPreviewView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ struct CameraPreviewView: View {
1515

1616
@StateObject var model: CameraPreviewViewModel
1717

18-
init(model: CameraPreviewViewModel = CameraPreviewViewModel()) {
18+
init(model: CameraPreviewViewModel = CameraPreviewViewModel(cameraPosition: .front)) {
1919
self._model = StateObject(wrappedValue: model)
2020
}
2121

Sources/FaceLiveness/Views/GetReadyPage/CameraPreviewViewModel.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,18 @@ class CameraPreviewViewModel: NSObject, ObservableObject {
1616
@Published var buffer: CVPixelBuffer?
1717

1818
var previewCaptureSession: LivenessCaptureSession?
19+
let cameraPosition: LivenessCaptureDevicePosition
1920

20-
override init() {
21+
init(cameraPosition: LivenessCaptureDevicePosition) {
22+
self.cameraPosition = cameraPosition
23+
2124
super.init()
2225
setupSubscriptions()
2326

2427
let avCaptureDevice = AVCaptureDevice.DiscoverySession(
2528
deviceTypes: [.builtInWideAngleCamera],
2629
mediaType: .video,
27-
position: .front
30+
position: cameraPosition == .front ? .front : .back
2831
).devices.first
2932

3033
let outputDelegate = CameraPreviewOutputSampleBufferDelegate { [weak self] buffer in

Sources/FaceLiveness/Views/GetReadyPage/GetReadyPageView.swift

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,24 @@ struct GetReadyPageView: View {
1212
let beginCheckButtonDisabled: Bool
1313
let onBegin: () -> Void
1414
let challenge: Challenge
15+
let cameraPosition: LivenessCaptureDevicePosition
1516

1617
init(
1718
onBegin: @escaping () -> Void,
1819
beginCheckButtonDisabled: Bool = false,
19-
challenge: Challenge
20+
challenge: Challenge,
21+
cameraPosition: LivenessCaptureDevicePosition
2022
) {
2123
self.onBegin = onBegin
2224
self.beginCheckButtonDisabled = beginCheckButtonDisabled
2325
self.challenge = challenge
26+
self.cameraPosition = cameraPosition
2427
}
2528

2629
var body: some View {
2730
VStack {
2831
ZStack {
29-
CameraPreviewView()
32+
CameraPreviewView(model: CameraPreviewViewModel(cameraPosition: cameraPosition))
3033
VStack {
3134
WarningBox(
3235
titleText: LocalizedStrings.get_ready_photosensitivity_title,
@@ -79,6 +82,7 @@ struct GetReadyPageView_Previews: PreviewProvider {
7982
static var previews: some View {
8083
GetReadyPageView(onBegin: {},
8184
challenge: .init(version: "2.0.0",
82-
type: .faceMovementAndLightChallenge))
85+
type: .faceMovementAndLightChallenge),
86+
cameraPosition: .front)
8387
}
8488
}

Sources/FaceLiveness/Views/Liveness/FaceLivenessDetectionView.swift

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public struct FaceLivenessDetectorView: View {
2020
@State var displayingCameraPermissionsNeededAlert = false
2121

2222
let disableStartView: Bool
23+
let cameraPosition: LivenessCaptureDevicePosition
2324
let onCompletion: (Result<Void, FaceLivenessDetectionError>) -> Void
2425

2526
let sessionTask: Task<FaceLivenessSession, Error>
@@ -29,11 +30,13 @@ public struct FaceLivenessDetectorView: View {
2930
credentialsProvider: AWSCredentialsProvider? = nil,
3031
region: String,
3132
disableStartView: Bool = false,
33+
cameraPosition: LivenessCaptureDevicePosition,
3234
isPresented: Binding<Bool>,
3335
onCompletion: @escaping (Result<Void, FaceLivenessDetectionError>) -> Void
3436
) {
3537
self.disableStartView = disableStartView
3638
self._isPresented = isPresented
39+
self.cameraPosition = cameraPosition
3740
self.onCompletion = onCompletion
3841

3942
self.sessionTask = Task {
@@ -60,7 +63,7 @@ public struct FaceLivenessDetectorView: View {
6063
let avCpatureDevice = AVCaptureDevice.DiscoverySession(
6164
deviceTypes: [.builtInWideAngleCamera],
6265
mediaType: .video,
63-
position: .front
66+
position: cameraPosition == .front ? .front : .back
6467
).devices.first
6568

6669
let captureSession = LivenessCaptureSession(
@@ -89,13 +92,15 @@ public struct FaceLivenessDetectorView: View {
8992
credentialsProvider: AWSCredentialsProvider? = nil,
9093
region: String,
9194
disableStartView: Bool = false,
95+
cameraPosition: LivenessCaptureDevicePosition,
9296
isPresented: Binding<Bool>,
9397
onCompletion: @escaping (Result<Void, FaceLivenessDetectionError>) -> Void,
9498
captureSession: LivenessCaptureSession
9599
) {
96100
self.disableStartView = disableStartView
97101
self._isPresented = isPresented
98102
self.onCompletion = onCompletion
103+
self.cameraPosition = cameraPosition
99104

100105
self.sessionTask = Task {
101106
let session = try await AWSPredictionsPlugin.startFaceLivenessSession(
@@ -166,21 +171,22 @@ public struct FaceLivenessDetectorView: View {
166171
do {
167172
let newState = disableStartView
168173
? DisplayState.displayingLiveness
169-
: DisplayState.displayingGetReadyView(challenge)
174+
: DisplayState.displayingGetReadyView(challenge, cameraPosition)
170175
guard self.displayState != newState else { return }
171176
self.displayState = newState
172177
}
173178
}
174179
}
175180

176-
case .displayingGetReadyView(let challenge):
181+
case .displayingGetReadyView(let challenge, let cameraPosition):
177182
GetReadyPageView(
178183
onBegin: {
179184
guard displayState != .displayingLiveness else { return }
180185
displayState = .displayingLiveness
181186
},
182187
beginCheckButtonDisabled: false,
183-
challenge: challenge
188+
challenge: challenge,
189+
cameraPosition: cameraPosition
184190
)
185191
.onAppear {
186192
DispatchQueue.main.async {
@@ -276,7 +282,7 @@ public struct FaceLivenessDetectorView: View {
276282
enum DisplayState: Equatable {
277283
case awaitingChallengeType
278284
case awaitingLivenessSession(Challenge)
279-
case displayingGetReadyView(Challenge)
285+
case displayingGetReadyView(Challenge, LivenessCaptureDevicePosition)
280286
case displayingLiveness
281287
case awaitingCameraPermission
282288

@@ -286,8 +292,8 @@ enum DisplayState: Equatable {
286292
return true
287293
case (let .awaitingLivenessSession(c1), let .awaitingLivenessSession(c2)):
288294
return c1.type == c2.type && c1.version == c2.version
289-
case (let .displayingGetReadyView(c1), let .displayingGetReadyView(c2)):
290-
return c1.type == c2.type && c1.version == c2.version
295+
case (let .displayingGetReadyView(c1, position1), let .displayingGetReadyView(c2, position2)):
296+
return c1.type == c2.type && c1.version == c2.version && position1 == position2
291297
case (.displayingLiveness, .displayingLiveness):
292298
return true
293299
case (.awaitingCameraPermission, .awaitingCameraPermission):

Tests/FaceLivenessTests/CredentialsProviderTestCase.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ final class CredentialsProviderTestCase: XCTestCase {
6666
sessionID: UUID().uuidString,
6767
credentialsProvider: credentialsProvider,
6868
region: "us-east-1",
69+
cameraPosition: .front,
6970
isPresented: .constant(true),
7071
onCompletion: { _ in }
7172
)
@@ -102,6 +103,7 @@ final class CredentialsProviderTestCase: XCTestCase {
102103
sessionID: UUID().uuidString,
103104
credentialsProvider: credentialsProvider,
104105
region: "us-east-1",
106+
cameraPosition: .front,
105107
isPresented: .constant(true),
106108
onCompletion: { _ in }
107109
)

0 commit comments

Comments
 (0)