From cf4882b152685e2a8e38ba5146ea98231a64d244 Mon Sep 17 00:00:00 2001 From: Marc Rousavy Date: Thu, 21 Sep 2023 16:29:46 +0200 Subject: [PATCH] feat: Add support for LiDAR, TrueDepth, External (USB) and Continuity Camera Devices (iOS 17) (#1824) * feat: Add support for LiDAR, TrueDepth, External (USB) and Continuity Camera Devices (iOS 17) * Rename `devices` -> `physicalDevices` * fix: Comment out iOS 17 cameras for now * fix: Move `supportsDepthCapture` to `format` * fix: Fall back to `wide-angle-camera` for any unknown types * Update CameraPage.tsx * `descriptor` -> `physicalDeviceDescriptor` * Update CameraDevice.ts * Format * feat: Expose `userPreferredCameraDevice` Uses the new iOS 17 API where the user can prefer a default device, otherwise fall back to the first device of the available ones * fix: Expose as property * Add TODO comments * fix: Format code * fix: Compile below Swift 5.9 --- .github/ISSUE_TEMPLATE/BUG_REPORT.yml | 1 - .../mrousavy/camera/CameraDevicesManager.kt | 10 +++- .../camera/core/CameraDeviceDetails.kt | 4 +- package/example/src/CameraPage.tsx | 2 +- package/ios/CameraDevicesManager.swift | 58 +++++++++++-------- package/ios/CameraView+AVCaptureSession.swift | 2 + .../AVCaptureDevice+toDictionary.swift | 34 +++++++++++ .../AVCaptureDevice.Format+toDictionary.swift | 1 + ...VCaptureDevice.DeviceType+descriptor.swift | 38 ------------ ....DeviceType+physicalDeviceDescriptor.swift | 33 +++++++++++ .../VisionCamera.xcodeproj/project.pbxproj | 12 ++-- package/src/CameraDevice.ts | 20 +++---- package/src/CameraDevices.ts | 2 + package/src/devices/getCameraDevice.ts | 4 +- 14 files changed, 136 insertions(+), 85 deletions(-) create mode 100644 package/ios/Extensions/AVCaptureDevice+toDictionary.swift delete mode 100644 package/ios/Parsers/AVCaptureDevice.DeviceType+descriptor.swift create mode 100644 package/ios/Parsers/AVCaptureDevice.DeviceType+physicalDeviceDescriptor.swift diff --git a/.github/ISSUE_TEMPLATE/BUG_REPORT.yml b/.github/ISSUE_TEMPLATE/BUG_REPORT.yml index 4bc8e38..55fa3c9 100644 --- a/.github/ISSUE_TEMPLATE/BUG_REPORT.yml +++ b/.github/ISSUE_TEMPLATE/BUG_REPORT.yml @@ -85,7 +85,6 @@ body: "maxZoom": 123.75, "name": "Back Dual Wide Camera", "position": "back", - "supportsDepthCapture": false, "supportsFocus": true, "supportsLowLightBoost": false, "supportsParallelVideoProcessing": true, diff --git a/package/android/src/main/java/com/mrousavy/camera/CameraDevicesManager.kt b/package/android/src/main/java/com/mrousavy/camera/CameraDevicesManager.kt index e41096d..a627397 100644 --- a/package/android/src/main/java/com/mrousavy/camera/CameraDevicesManager.kt +++ b/package/android/src/main/java/com/mrousavy/camera/CameraDevicesManager.kt @@ -73,7 +73,15 @@ class CameraDevicesManager(private val reactContext: ReactApplicationContext) : override fun hasConstants(): Boolean = true - override fun getConstants(): MutableMap = mutableMapOf("availableCameraDevices" to getDevicesJson()) + override fun getConstants(): MutableMap { + val devices = getDevicesJson() + val preferredDevice = if (devices.size() > 0) devices.getMap(0) else null + + return mutableMapOf( + "availableCameraDevices" to devices, + "userPreferredCameraDevice" to preferredDevice + ) + } // Required for NativeEventEmitter, this is just a dummy implementation: @ReactMethod diff --git a/package/android/src/main/java/com/mrousavy/camera/core/CameraDeviceDetails.kt b/package/android/src/main/java/com/mrousavy/camera/core/CameraDeviceDetails.kt index f9a11b6..015f3c0 100644 --- a/package/android/src/main/java/com/mrousavy/camera/core/CameraDeviceDetails.kt +++ b/package/android/src/main/java/com/mrousavy/camera/core/CameraDeviceDetails.kt @@ -183,6 +183,7 @@ class CameraDeviceDetails(private val cameraManager: CameraManager, private val map.putDouble("fieldOfView", getFieldOfView()) map.putBoolean("supportsVideoHDR", supportsVideoHdr) map.putBoolean("supportsPhotoHDR", supportsPhotoHdr) + map.putBoolean("supportsDepthCapture", supportsDepthCapture) map.putString("autoFocusSystem", "contrast-detection") // TODO: Is this wrong? map.putArray("videoStabilizationModes", createStabilizationModes()) map.putArray("pixelFormats", createPixelFormats(videoSize)) @@ -192,14 +193,13 @@ class CameraDeviceDetails(private val cameraManager: CameraManager, private val fun toMap(): ReadableMap { val map = Arguments.createMap() map.putString("id", cameraId) - map.putArray("devices", getDeviceTypes()) + map.putArray("physicalDevices", getDeviceTypes()) map.putString("position", lensFacing.unionValue) map.putString("name", name) map.putBoolean("hasFlash", hasFlash) map.putBoolean("hasTorch", hasFlash) map.putBoolean("isMultiCam", isMultiCam) map.putBoolean("supportsRawCapture", supportsRawCapture) - map.putBoolean("supportsDepthCapture", supportsDepthCapture) map.putBoolean("supportsLowLightBoost", supportsLowLightBoost) map.putBoolean("supportsFocus", true) // I believe every device here supports focussing map.putDouble("minZoom", minZoom) diff --git a/package/example/src/CameraPage.tsx b/package/example/src/CameraPage.tsx index 4eead54..93a501a 100644 --- a/package/example/src/CameraPage.tsx +++ b/package/example/src/CameraPage.tsx @@ -216,7 +216,7 @@ export function CameraPage({ navigation }: Props): React.ReactElement { )} {supports60Fps && ( setTargetFps((t) => (t === 30 ? 60 : 30))}> - {`${targetFps} FPS`} + {`${targetFps}\nFPS`} )} {supportsHdr && ( diff --git a/package/ios/CameraDevicesManager.swift b/package/ios/CameraDevicesManager.swift index 786de6c..a7746ad 100644 --- a/package/ios/CameraDevicesManager.swift +++ b/package/ios/CameraDevicesManager.swift @@ -37,47 +37,55 @@ class CameraDevicesManager: RCTEventEmitter { } override func constantsToExport() -> [AnyHashable: Any]! { + let devices = getDevicesJson() + let preferredDevice: [String: Any] + // TODO: Remove this #if once Xcode 15 is rolled out + #if swift(>=5.9) + if #available(iOS 17.0, *), + let userPreferred = AVCaptureDevice.userPreferredCamera { + preferredDevice = userPreferred.toDictionary() + } else { + preferredDevice = devices[0] + } + #else + preferredDevice = devices[0] + #endif + return [ - "availableCameraDevices": getDevicesJson(), + "availableCameraDevices": devices, + "userPreferredCameraDevice": preferredDevice, ] } private func getDevicesJson() -> [[String: Any]] { return discoverySession.devices.map { - return [ - "id": $0.uniqueID, - "devices": $0.physicalDevices.map(\.deviceType.descriptor), - "position": $0.position.descriptor, - "name": $0.localizedName, - "hasFlash": $0.hasFlash, - "hasTorch": $0.hasTorch, - "minZoom": $0.minAvailableVideoZoomFactor, - "neutralZoom": $0.neutralZoomFactor, - "maxZoom": $0.maxAvailableVideoZoomFactor, - "isMultiCam": $0.isMultiCam, - "supportsDepthCapture": false, // TODO: supportsDepthCapture - "supportsRawCapture": false, // TODO: supportsRawCapture - "supportsLowLightBoost": $0.isLowLightBoostSupported, - "supportsFocus": $0.isFocusPointOfInterestSupported, - "hardwareLevel": "full", - "sensorOrientation": "portrait", // TODO: Sensor Orientation? - "formats": $0.formats.map { format -> [String: Any] in - format.toDictionary() - }, - ] + return $0.toDictionary() } } private static func getAllDeviceTypes() -> [AVCaptureDevice.DeviceType] { var deviceTypes: [AVCaptureDevice.DeviceType] = [] + deviceTypes.append(.builtInDualCamera) + deviceTypes.append(.builtInWideAngleCamera) + deviceTypes.append(.builtInTelephotoCamera) + deviceTypes.append(.builtInTrueDepthCamera) if #available(iOS 13.0, *) { deviceTypes.append(.builtInTripleCamera) deviceTypes.append(.builtInDualWideCamera) deviceTypes.append(.builtInUltraWideCamera) } - deviceTypes.append(.builtInDualCamera) - deviceTypes.append(.builtInWideAngleCamera) - deviceTypes.append(.builtInTelephotoCamera) + if #available(iOS 15.4, *) { + deviceTypes.append(.builtInLiDARDepthCamera) + } + + // iOS 17 specifics: + // This is only reported if `NSCameraUseExternalDeviceType` is set to true in Info.plist, + // otherwise external devices are just reported as wide-angle-cameras + // deviceTypes.append(.external) + // This is only reported if `NSCameraUseContinuityCameraDeviceType` is set to true in Info.plist, + // otherwise continuity camera devices are just reported as wide-angle-cameras + // deviceTypes.append(.continuityCamera) + return deviceTypes } } diff --git a/package/ios/CameraView+AVCaptureSession.swift b/package/ios/CameraView+AVCaptureSession.swift index 2d51136..34f71a0 100644 --- a/package/ios/CameraView+AVCaptureSession.swift +++ b/package/ios/CameraView+AVCaptureSession.swift @@ -84,6 +84,8 @@ extension CameraView { photoOutput!.isDualCameraDualPhotoDeliveryEnabled = photoOutput!.isDualCameraDualPhotoDeliverySupported } } + // TODO: Enable isResponsiveCaptureEnabled? (iOS 17+) + // TODO: Enable isFastCapturePrioritizationEnabled? (iOS 17+) if enableDepthData { photoOutput!.isDepthDataDeliveryEnabled = photoOutput!.isDepthDataDeliverySupported } diff --git a/package/ios/Extensions/AVCaptureDevice+toDictionary.swift b/package/ios/Extensions/AVCaptureDevice+toDictionary.swift new file mode 100644 index 0000000..93dd518 --- /dev/null +++ b/package/ios/Extensions/AVCaptureDevice+toDictionary.swift @@ -0,0 +1,34 @@ +// +// AVCaptureDevice+toDictionary.swift +// VisionCamera +// +// Created by Marc Rousavy on 21.09.23. +// Copyright © 2023 mrousavy. All rights reserved. +// + +import AVFoundation + +extension AVCaptureDevice { + func toDictionary() -> [String: Any] { + return [ + "id": uniqueID, + "physicalDevices": physicalDevices.map(\.deviceType.physicalDeviceDescriptor), + "position": position.descriptor, + "name": localizedName, + "hasFlash": hasFlash, + "hasTorch": hasTorch, + "minZoom": minAvailableVideoZoomFactor, + "neutralZoom": neutralZoomFactor, + "maxZoom": maxAvailableVideoZoomFactor, + "isMultiCam": isMultiCam, + "supportsRawCapture": false, // TODO: supportsRawCapture + "supportsLowLightBoost": isLowLightBoostSupported, + "supportsFocus": isFocusPointOfInterestSupported, + "hardwareLevel": "full", + "sensorOrientation": "portrait", // TODO: Sensor Orientation? + "formats": formats.map { format -> [String: Any] in + format.toDictionary() + }, + ] + } +} diff --git a/package/ios/Extensions/AVCaptureDevice.Format+toDictionary.swift b/package/ios/Extensions/AVCaptureDevice.Format+toDictionary.swift index f34f3ff..9260c31 100644 --- a/package/ios/Extensions/AVCaptureDevice.Format+toDictionary.swift +++ b/package/ios/Extensions/AVCaptureDevice.Format+toDictionary.swift @@ -55,6 +55,7 @@ extension AVCaptureDevice.Format { "minFps": minFrameRate, "maxFps": maxFrameRate, "pixelFormats": pixelFormats.map(\.unionValue), + "supportsDepthCapture": !supportedDepthDataFormats.isEmpty, ] } } diff --git a/package/ios/Parsers/AVCaptureDevice.DeviceType+descriptor.swift b/package/ios/Parsers/AVCaptureDevice.DeviceType+descriptor.swift deleted file mode 100644 index ae0f966..0000000 --- a/package/ios/Parsers/AVCaptureDevice.DeviceType+descriptor.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// AVCaptureDevice.DeviceType+descriptor.swift -// mrousavy -// -// Created by Marc Rousavy on 15.12.20. -// Copyright © 2020 mrousavy. All rights reserved. -// - -import AVFoundation -import Foundation - -extension AVCaptureDevice.DeviceType { - var descriptor: String { - if #available(iOS 13.0, *) { - switch self { - case .builtInDualWideCamera: - return "dual-wide-camera" - case .builtInTripleCamera: - return "triple-camera" - case .builtInUltraWideCamera: - return "ultra-wide-angle-camera" - default: - break - } - } - switch self { - case .builtInDualCamera: - return "dual-camera" - case .builtInTelephotoCamera: - return "telephoto-camera" - case .builtInWideAngleCamera: - return "wide-angle-camera" - default: - // e.g. `.builtInTrueDepthCamera` - fatalError("AVCaptureDevice.Position has unknown state.") - } - } -} diff --git a/package/ios/Parsers/AVCaptureDevice.DeviceType+physicalDeviceDescriptor.swift b/package/ios/Parsers/AVCaptureDevice.DeviceType+physicalDeviceDescriptor.swift new file mode 100644 index 0000000..f88dd3e --- /dev/null +++ b/package/ios/Parsers/AVCaptureDevice.DeviceType+physicalDeviceDescriptor.swift @@ -0,0 +1,33 @@ +// +// AVCaptureDevice.DeviceType+physicalDeviceDescriptor.swift +// mrousavy +// +// Created by Marc Rousavy on 15.12.20. +// Copyright © 2020 mrousavy. All rights reserved. +// + +import AVFoundation +import Foundation + +extension AVCaptureDevice.DeviceType { + /** + Gets a descriptor if this is a physical device (wide, ultra-wide and telephoto), or "unknown-camera" otherwise (TrueDepth, LiDAR, InfraRed, USB, ..) + */ + var physicalDeviceDescriptor: String { + if #available(iOS 13.0, *) { + if self == .builtInUltraWideCamera { + return "ultra-wide-angle-camera" + } + } + switch self { + case .builtInTelephotoCamera: + return "telephoto-camera" + case .builtInWideAngleCamera: + return "wide-angle-camera" + default: + // e.g. Infra-Red, LiDAR, Depth Data, USB or Continuity Camera Devices + ReactLogger.log(level: .error, message: "Unknown AVCaptureDevice.DeviceType (\(rawValue))! Falling back to wide-angle-camera..") + return "wide-angle-camera" + } + } +} diff --git a/package/ios/VisionCamera.xcodeproj/project.pbxproj b/package/ios/VisionCamera.xcodeproj/project.pbxproj index 677b965..64e135b 100644 --- a/package/ios/VisionCamera.xcodeproj/project.pbxproj +++ b/package/ios/VisionCamera.xcodeproj/project.pbxproj @@ -22,6 +22,7 @@ B86DC974260E310600FB17B2 /* CameraView+AVAudioSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86DC973260E310600FB17B2 /* CameraView+AVAudioSession.swift */; }; B86DC977260E315100FB17B2 /* CameraView+AVCaptureSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86DC976260E315100FB17B2 /* CameraView+AVCaptureSession.swift */; }; B87B11BF2A8E63B700732EBF /* PixelFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = B87B11BE2A8E63B700732EBF /* PixelFormat.swift */; }; + B881D35E2ABC775E009B21C8 /* AVCaptureDevice+toDictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = B881D35D2ABC775E009B21C8 /* AVCaptureDevice+toDictionary.swift */; }; B882721026AEB1A100B14107 /* AVCaptureConnection+setInterfaceOrientation.swift in Sources */ = {isa = PBXBuildFile; fileRef = B882720F26AEB1A100B14107 /* AVCaptureConnection+setInterfaceOrientation.swift */; }; B887518525E0102000DB86D6 /* PhotoCaptureDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B887515C25E0102000DB86D6 /* PhotoCaptureDelegate.swift */; }; B887518625E0102000DB86D6 /* CameraView+RecordVideo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B887515D25E0102000DB86D6 /* CameraView+RecordVideo.swift */; }; @@ -44,7 +45,7 @@ B887519A25E0102000DB86D6 /* AVVideoCodecType+descriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B887517525E0102000DB86D6 /* AVVideoCodecType+descriptor.swift */; }; B887519C25E0102000DB86D6 /* AVCaptureDevice.TorchMode+descriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B887517725E0102000DB86D6 /* AVCaptureDevice.TorchMode+descriptor.swift */; }; B887519E25E0102000DB86D6 /* AVCapturePhotoOutput.QualityPrioritization+descriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B887517925E0102000DB86D6 /* AVCapturePhotoOutput.QualityPrioritization+descriptor.swift */; }; - B887519F25E0102000DB86D6 /* AVCaptureDevice.DeviceType+descriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B887517A25E0102000DB86D6 /* AVCaptureDevice.DeviceType+descriptor.swift */; }; + B887519F25E0102000DB86D6 /* AVCaptureDevice.DeviceType+physicalDeviceDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B887517A25E0102000DB86D6 /* AVCaptureDevice.DeviceType+physicalDeviceDescriptor.swift */; }; B88751A025E0102000DB86D6 /* AVAuthorizationStatus+descriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B887517B25E0102000DB86D6 /* AVAuthorizationStatus+descriptor.swift */; }; B88751A125E0102000DB86D6 /* AVCaptureDevice.Position+descriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B887517C25E0102000DB86D6 /* AVCaptureDevice.Position+descriptor.swift */; }; B88751A325E0102000DB86D6 /* AVCaptureDevice.FlashMode+descriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B887517E25E0102000DB86D6 /* AVCaptureDevice.FlashMode+descriptor.swift */; }; @@ -99,6 +100,7 @@ B86DC973260E310600FB17B2 /* CameraView+AVAudioSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CameraView+AVAudioSession.swift"; sourceTree = ""; }; B86DC976260E315100FB17B2 /* CameraView+AVCaptureSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CameraView+AVCaptureSession.swift"; sourceTree = ""; }; B87B11BE2A8E63B700732EBF /* PixelFormat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PixelFormat.swift; sourceTree = ""; }; + B881D35D2ABC775E009B21C8 /* AVCaptureDevice+toDictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AVCaptureDevice+toDictionary.swift"; sourceTree = ""; }; B882720F26AEB1A100B14107 /* AVCaptureConnection+setInterfaceOrientation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AVCaptureConnection+setInterfaceOrientation.swift"; sourceTree = ""; }; B887515C25E0102000DB86D6 /* PhotoCaptureDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhotoCaptureDelegate.swift; sourceTree = ""; }; B887515D25E0102000DB86D6 /* CameraView+RecordVideo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CameraView+RecordVideo.swift"; sourceTree = ""; }; @@ -122,7 +124,7 @@ B887517525E0102000DB86D6 /* AVVideoCodecType+descriptor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AVVideoCodecType+descriptor.swift"; sourceTree = ""; }; B887517725E0102000DB86D6 /* AVCaptureDevice.TorchMode+descriptor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AVCaptureDevice.TorchMode+descriptor.swift"; sourceTree = ""; }; B887517925E0102000DB86D6 /* AVCapturePhotoOutput.QualityPrioritization+descriptor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AVCapturePhotoOutput.QualityPrioritization+descriptor.swift"; sourceTree = ""; }; - B887517A25E0102000DB86D6 /* AVCaptureDevice.DeviceType+descriptor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AVCaptureDevice.DeviceType+descriptor.swift"; sourceTree = ""; }; + B887517A25E0102000DB86D6 /* AVCaptureDevice.DeviceType+physicalDeviceDescriptor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AVCaptureDevice.DeviceType+physicalDeviceDescriptor.swift"; sourceTree = ""; }; B887517B25E0102000DB86D6 /* AVAuthorizationStatus+descriptor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AVAuthorizationStatus+descriptor.swift"; sourceTree = ""; }; B887517C25E0102000DB86D6 /* AVCaptureDevice.Position+descriptor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AVCaptureDevice.Position+descriptor.swift"; sourceTree = ""; }; B887517E25E0102000DB86D6 /* AVCaptureDevice.FlashMode+descriptor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AVCaptureDevice.FlashMode+descriptor.swift"; sourceTree = ""; }; @@ -211,6 +213,7 @@ B887516625E0102000DB86D6 /* AVCaptureDevice+physicalDevices.swift */, B887516725E0102000DB86D6 /* AVFrameRateRange+includes.swift */, B887516825E0102000DB86D6 /* AVCapturePhotoOutput+mirror.swift */, + B881D35D2ABC775E009B21C8 /* AVCaptureDevice+toDictionary.swift */, B887516925E0102000DB86D6 /* AVCaptureDevice.Format+matchesFilter.swift */, B887516A25E0102000DB86D6 /* AVCaptureDevice.Format+toDictionary.swift */, B88B47462667C8E00091F538 /* AVCaptureSession+setVideoStabilizationMode.swift */, @@ -239,7 +242,7 @@ B887517525E0102000DB86D6 /* AVVideoCodecType+descriptor.swift */, B887517725E0102000DB86D6 /* AVCaptureDevice.TorchMode+descriptor.swift */, B887517925E0102000DB86D6 /* AVCapturePhotoOutput.QualityPrioritization+descriptor.swift */, - B887517A25E0102000DB86D6 /* AVCaptureDevice.DeviceType+descriptor.swift */, + B887517A25E0102000DB86D6 /* AVCaptureDevice.DeviceType+physicalDeviceDescriptor.swift */, B887517B25E0102000DB86D6 /* AVAuthorizationStatus+descriptor.swift */, B887517C25E0102000DB86D6 /* AVCaptureDevice.Position+descriptor.swift */, B887517E25E0102000DB86D6 /* AVCaptureDevice.FlashMode+descriptor.swift */, @@ -408,9 +411,10 @@ B887519A25E0102000DB86D6 /* AVVideoCodecType+descriptor.swift in Sources */, B88751A825E0102000DB86D6 /* CameraError.swift in Sources */, B85F7AE92A77BB680089C539 /* FrameProcessorPlugin.m in Sources */, + B881D35E2ABC775E009B21C8 /* AVCaptureDevice+toDictionary.swift in Sources */, B87B11BF2A8E63B700732EBF /* PixelFormat.swift in Sources */, B88751A625E0102000DB86D6 /* CameraViewManager.swift in Sources */, - B887519F25E0102000DB86D6 /* AVCaptureDevice.DeviceType+descriptor.swift in Sources */, + B887519F25E0102000DB86D6 /* AVCaptureDevice.DeviceType+physicalDeviceDescriptor.swift in Sources */, B8D22CDC2642DB4D00234472 /* AVAssetWriterInputPixelBufferAdaptor+initWithVideoSettings.swift in Sources */, B84760DF2608F57D004C3180 /* CameraQueues.swift in Sources */, B8446E502ABA14C900E56077 /* CameraDevicesManager.m in Sources */, diff --git a/package/src/CameraDevice.ts b/package/src/CameraDevice.ts index 6c938c6..fb1f1ec 100644 --- a/package/src/CameraDevice.ts +++ b/package/src/CameraDevice.ts @@ -14,7 +14,7 @@ export type CameraPosition = 'front' | 'back' | 'external'; * Indentifiers for a physical camera (one that actually exists on the back/front of the device) * * * `"ultra-wide-angle-camera"`: A built-in camera with a shorter focal length than that of a wide-angle camera. (focal length between below 24mm) - * * `"wide-angle-camera"`: A built-in wide-angle camera. (focal length between 24mm and 35mm) + * * `"wide-angle-camera"`: A built-in wide-angle camera. (focal length between 24mm and 43mm) * * `"telephoto-camera"`: A built-in camera device with a longer focal length than a wide-angle camera. (focal length between above 85mm) * * Some Camera devices consist of multiple physical devices. They can be interpreted as _logical devices_, for example: @@ -89,6 +89,10 @@ export interface CameraDeviceFormat { * Specifies whether this format supports HDR mode for photo capture */ supportsPhotoHDR: boolean; + /** + * Specifies whether this format supports delivering depth data for photo or video capture. + */ + supportsDepthCapture: boolean; /** * The minum frame rate this Format needs to run at. High resolution formats often run at lower frame rates. */ @@ -121,14 +125,14 @@ export interface CameraDevice { */ id: string; /** - * The physical devices this `CameraDevice` contains. + * The physical devices this `CameraDevice` consists of. * - * * If this camera device is a **logical camera** (combination of multiple physical cameras), there are multiple cameras in this array. - * * If this camera device is a **physical camera**, there is only a single element in this array. + * * If this camera device is a **logical camera** (combination of multiple physical cameras, e.g. "Triple Camera"), there are multiple cameras in this array. + * * If this camera device is a **physical camera** (e.g. "wide-angle-camera"), there is only a single element in this array. * * You can check if the camera is a logical multi-camera by using the `isMultiCam` property. */ - devices: PhysicalCameraDeviceType[]; + physicalDevices: PhysicalCameraDeviceType[]; /** * Specifies the physical position of this camera. (back or front) */ @@ -187,12 +191,6 @@ export interface CameraDevice { * Whether this camera device supports low light boost. */ supportsLowLightBoost: boolean; - /** - * Whether this camera supports taking photos with depth data. - * - * **! Work in Progress !** - */ - supportsDepthCapture: boolean; /** * Whether this camera supports taking photos in RAW format * diff --git a/package/src/CameraDevices.ts b/package/src/CameraDevices.ts index 44125d9..d996752 100644 --- a/package/src/CameraDevices.ts +++ b/package/src/CameraDevices.ts @@ -4,6 +4,7 @@ import { CameraDevice } from './CameraDevice'; const CameraDevicesManager = NativeModules.CameraDevices as { getConstants: () => { availableCameraDevices: CameraDevice[]; + userPreferredCameraDevice: CameraDevice | undefined; }; }; @@ -18,6 +19,7 @@ eventEmitter.addListener(DEVICES_CHANGED_NAME, (newDevices: CameraDevice[]) => { }); export const CameraDevices = { + userPreferredCameraDevice: constants.userPreferredCameraDevice, getAvailableCameraDevices: () => devices, addCameraDevicesChangedListener: (callback: (newDevices: CameraDevice[]) => void) => { return eventEmitter.addListener(DEVICES_CHANGED_NAME, callback); diff --git a/package/src/devices/getCameraDevice.ts b/package/src/devices/getCameraDevice.ts index 78137f3..61c2f21 100644 --- a/package/src/devices/getCameraDevice.ts +++ b/package/src/devices/getCameraDevice.ts @@ -43,11 +43,11 @@ export function getCameraDevice(devices: CameraDevice[], position: CameraPositio // 1. user wants all cameras ([ultra-wide, wide, tele]) to zoom. prefer those devices that have all 3 cameras. // 2. user wants only one ([wide]) for faster performance. prefer those devices that only have one camera, if they have more, we rank them lower. if (filter.physicalDevices != null) { - for (const device of left.devices) { + for (const device of left.physicalDevices) { if (filter.physicalDevices.includes(device)) leftPoints += 1; else leftPoints -= 1; } - for (const device of right.devices) { + for (const device of right.physicalDevices) { if (filter.physicalDevices.includes(device)) rightPoints += 1; else rightPoints -= 1; }