chore: Cleanup void returns (#187)

* Place `return` in `return [void]` on separate line

* format

* Update CameraView+RecordVideo.swift

* f
This commit is contained in:
Marc Rousavy 2021-06-09 11:14:49 +02:00 committed by GitHub
parent 68a716b506
commit 16f2a7cdec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 110 additions and 73 deletions

View File

@ -31,7 +31,8 @@ extension CameraView {
if enableAudio { if enableAudio {
let audioPermissionStatus = AVCaptureDevice.authorizationStatus(for: .audio) let audioPermissionStatus = AVCaptureDevice.authorizationStatus(for: .audio)
if audioPermissionStatus != .authorized { if audioPermissionStatus != .authorized {
return invokeOnError(.permission(.microphone)) invokeOnError(.permission(.microphone))
return
} }
} }
@ -44,16 +45,19 @@ extension CameraView {
if enableAudio { if enableAudio {
ReactLogger.log(level: .info, message: "Adding Audio input...") ReactLogger.log(level: .info, message: "Adding Audio input...")
guard let audioDevice = AVCaptureDevice.default(for: .audio) else { guard let audioDevice = AVCaptureDevice.default(for: .audio) else {
return invokeOnError(.device(.microphoneUnavailable)) invokeOnError(.device(.microphoneUnavailable))
return
} }
audioDeviceInput = try AVCaptureDeviceInput(device: audioDevice) audioDeviceInput = try AVCaptureDeviceInput(device: audioDevice)
guard audioCaptureSession.canAddInput(audioDeviceInput!) else { guard audioCaptureSession.canAddInput(audioDeviceInput!) else {
return invokeOnError(.parameter(.unsupportedInput(inputDescriptor: "audio-input"))) invokeOnError(.parameter(.unsupportedInput(inputDescriptor: "audio-input")))
return
} }
audioCaptureSession.addInput(audioDeviceInput!) audioCaptureSession.addInput(audioDeviceInput!)
} }
} catch let error as NSError { } catch let error as NSError {
return invokeOnError(.device(.microphoneUnavailable), cause: error) invokeOnError(.device(.microphoneUnavailable), cause: error)
return
} }
// Audio Output // Audio Output
@ -65,7 +69,8 @@ extension CameraView {
ReactLogger.log(level: .info, message: "Adding Audio Data output...") ReactLogger.log(level: .info, message: "Adding Audio Data output...")
audioOutput = AVCaptureAudioDataOutput() audioOutput = AVCaptureAudioDataOutput()
guard audioCaptureSession.canAddOutput(audioOutput!) else { guard audioCaptureSession.canAddOutput(audioOutput!) else {
return invokeOnError(.parameter(.unsupportedOutput(outputDescriptor: "audio-output"))) invokeOnError(.parameter(.unsupportedOutput(outputDescriptor: "audio-output")))
return
} }
audioOutput!.setSampleBufferDelegate(self, queue: audioQueue) audioOutput!.setSampleBufferDelegate(self, queue: audioQueue)
audioCaptureSession.addOutput(audioOutput!) audioCaptureSession.addOutput(audioOutput!)

View File

@ -23,11 +23,13 @@ extension CameraView {
isReady = false isReady = false
#if targetEnvironment(simulator) #if targetEnvironment(simulator)
return invokeOnError(.device(.notAvailableOnSimulator)) invokeOnError(.device(.notAvailableOnSimulator))
return
#endif #endif
guard cameraId != nil else { guard cameraId != nil else {
return invokeOnError(.device(.noDevice)) invokeOnError(.device(.noDevice))
return
} }
let cameraId = self.cameraId! as String let cameraId = self.cameraId! as String
@ -43,9 +45,11 @@ extension CameraView {
do { do {
sessionPreset = try AVCaptureSession.Preset(withString: preset) sessionPreset = try AVCaptureSession.Preset(withString: preset)
} catch let EnumParserError.unsupportedOS(supportedOnOS: os) { } catch let EnumParserError.unsupportedOS(supportedOnOS: os) {
return invokeOnError(.parameter(.unsupportedOS(unionName: "Preset", receivedValue: preset, supportedOnOs: os))) invokeOnError(.parameter(.unsupportedOS(unionName: "Preset", receivedValue: preset, supportedOnOs: os)))
return
} catch { } catch {
return invokeOnError(.parameter(.invalid(unionName: "Preset", receivedValue: preset))) invokeOnError(.parameter(.invalid(unionName: "Preset", receivedValue: preset)))
return
} }
if sessionPreset != nil { if sessionPreset != nil {
if captureSession.canSetSessionPreset(sessionPreset!) { if captureSession.canSetSessionPreset(sessionPreset!) {
@ -66,15 +70,18 @@ extension CameraView {
} }
ReactLogger.log(level: .info, message: "Adding Video input...") ReactLogger.log(level: .info, message: "Adding Video input...")
guard let videoDevice = AVCaptureDevice(uniqueID: cameraId) else { guard let videoDevice = AVCaptureDevice(uniqueID: cameraId) else {
return invokeOnError(.device(.invalid)) invokeOnError(.device(.invalid))
return
} }
videoDeviceInput = try AVCaptureDeviceInput(device: videoDevice) videoDeviceInput = try AVCaptureDeviceInput(device: videoDevice)
guard captureSession.canAddInput(videoDeviceInput!) else { guard captureSession.canAddInput(videoDeviceInput!) else {
return invokeOnError(.parameter(.unsupportedInput(inputDescriptor: "video-input"))) invokeOnError(.parameter(.unsupportedInput(inputDescriptor: "video-input")))
return
} }
captureSession.addInput(videoDeviceInput!) captureSession.addInput(videoDeviceInput!)
} catch { } catch {
return invokeOnError(.device(.invalid)) invokeOnError(.device(.invalid))
return
} }
// pragma MARK: Capture Session Outputs // pragma MARK: Capture Session Outputs
@ -95,7 +102,8 @@ extension CameraView {
photoOutput!.isPortraitEffectsMatteDeliveryEnabled = photoOutput!.isPortraitEffectsMatteDeliverySupported && self.enablePortraitEffectsMatteDelivery photoOutput!.isPortraitEffectsMatteDeliveryEnabled = photoOutput!.isPortraitEffectsMatteDeliverySupported && self.enablePortraitEffectsMatteDelivery
} }
guard captureSession.canAddOutput(photoOutput!) else { guard captureSession.canAddOutput(photoOutput!) else {
return invokeOnError(.parameter(.unsupportedOutput(outputDescriptor: "photo-output"))) invokeOnError(.parameter(.unsupportedOutput(outputDescriptor: "photo-output")))
return
} }
captureSession.addOutput(photoOutput!) captureSession.addOutput(photoOutput!)
if videoDeviceInput!.device.position == .front { if videoDeviceInput!.device.position == .front {
@ -112,7 +120,8 @@ extension CameraView {
ReactLogger.log(level: .info, message: "Adding Video Data output...") ReactLogger.log(level: .info, message: "Adding Video Data output...")
videoOutput = AVCaptureVideoDataOutput() videoOutput = AVCaptureVideoDataOutput()
guard captureSession.canAddOutput(videoOutput!) else { guard captureSession.canAddOutput(videoOutput!) else {
return invokeOnError(.parameter(.unsupportedOutput(outputDescriptor: "video-output"))) invokeOnError(.parameter(.unsupportedOutput(outputDescriptor: "video-output")))
return
} }
videoOutput!.setSampleBufferDelegate(self, queue: videoQueue) videoOutput!.setSampleBufferDelegate(self, queue: videoQueue)
videoOutput!.alwaysDiscardsLateVideoFrames = true videoOutput!.alwaysDiscardsLateVideoFrames = true
@ -135,7 +144,8 @@ extension CameraView {
final func configureDevice() { final func configureDevice() {
ReactLogger.log(level: .info, message: "Configuring Device...") ReactLogger.log(level: .info, message: "Configuring Device...")
guard let device = videoDeviceInput?.device else { guard let device = videoDeviceInput?.device else {
return invokeOnError(.session(.cameraNotReady)) invokeOnError(.session(.cameraNotReady))
return
} }
do { do {
@ -151,7 +161,8 @@ extension CameraView {
} }
if hdr != nil { if hdr != nil {
if hdr == true && !device.activeFormat.isVideoHDRSupported { if hdr == true && !device.activeFormat.isVideoHDRSupported {
return invokeOnError(.format(.invalidHdr)) invokeOnError(.format(.invalidHdr))
return
} }
if !device.automaticallyAdjustsVideoHDREnabled { if !device.automaticallyAdjustsVideoHDREnabled {
if device.isVideoHDREnabled != hdr!.boolValue { if device.isVideoHDREnabled != hdr!.boolValue {
@ -161,7 +172,8 @@ extension CameraView {
} }
if lowLightBoost != nil { if lowLightBoost != nil {
if lowLightBoost == true && !device.isLowLightBoostSupported { if lowLightBoost == true && !device.isLowLightBoostSupported {
return invokeOnError(.device(.lowLightBoostNotSupported)) invokeOnError(.device(.lowLightBoostNotSupported))
return
} }
if device.automaticallyEnablesLowLightBoostWhenAvailable != lowLightBoost!.boolValue { if device.automaticallyEnablesLowLightBoostWhenAvailable != lowLightBoost!.boolValue {
device.automaticallyEnablesLowLightBoostWhenAvailable = lowLightBoost!.boolValue device.automaticallyEnablesLowLightBoostWhenAvailable = lowLightBoost!.boolValue
@ -174,7 +186,8 @@ extension CameraView {
device.unlockForConfiguration() device.unlockForConfiguration()
ReactLogger.log(level: .info, message: "Device successfully configured!") ReactLogger.log(level: .info, message: "Device successfully configured!")
} catch let error as NSError { } catch let error as NSError {
return invokeOnError(.device(.configureError), cause: error) invokeOnError(.device(.configureError), cause: error)
return
} }
} }
@ -190,7 +203,8 @@ extension CameraView {
return return
} }
guard let device = videoDeviceInput?.device else { guard let device = videoDeviceInput?.device else {
return invokeOnError(.session(.cameraNotReady)) invokeOnError(.session(.cameraNotReady))
return
} }
if device.activeFormat.matchesFilter(filter) { if device.activeFormat.matchesFilter(filter) {
@ -201,7 +215,8 @@ extension CameraView {
// get matching format // get matching format
let matchingFormats = device.formats.filter { $0.matchesFilter(filter) }.sorted { $0.isBetterThan($1) } let matchingFormats = device.formats.filter { $0.matchesFilter(filter) }.sorted { $0.isBetterThan($1) }
guard let format = matchingFormats.first else { guard let format = matchingFormats.first else {
return invokeOnError(.format(.invalidFormat)) invokeOnError(.format(.invalidFormat))
return
} }
do { do {
@ -210,7 +225,8 @@ extension CameraView {
device.unlockForConfiguration() device.unlockForConfiguration()
ReactLogger.log(level: .info, message: "Format successfully configured!") ReactLogger.log(level: .info, message: "Format successfully configured!")
} catch let error as NSError { } catch let error as NSError {
return invokeOnError(.device(.configureError), cause: error) invokeOnError(.device(.configureError), cause: error)
return
} }
} }

View File

@ -24,7 +24,8 @@ extension CameraView: AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureAud
var fileType = AVFileType.mov var fileType = AVFileType.mov
if let fileTypeOption = options["fileType"] as? String { if let fileTypeOption = options["fileType"] as? String {
guard let parsed = try? AVFileType(withString: fileTypeOption) else { guard let parsed = try? AVFileType(withString: fileTypeOption) else {
return callback.reject(error: .parameter(.invalid(unionName: "fileType", receivedValue: fileTypeOption))) callback.reject(error: .parameter(.invalid(unionName: "fileType", receivedValue: fileTypeOption)))
return
} }
fileType = parsed fileType = parsed
} }
@ -32,7 +33,8 @@ extension CameraView: AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureAud
let errorPointer = ErrorPointer(nilLiteral: ()) let errorPointer = ErrorPointer(nilLiteral: ())
let fileExtension = fileType.descriptor ?? "mov" let fileExtension = fileType.descriptor ?? "mov"
guard let tempFilePath = RCTTempFilePath(fileExtension, errorPointer) else { guard let tempFilePath = RCTTempFilePath(fileExtension, errorPointer) else {
return callback.reject(error: .capture(.createTempFileError), cause: errorPointer?.pointee) callback.reject(error: .capture(.createTempFileError), cause: errorPointer?.pointee)
return
} }
ReactLogger.log(level: .info, message: "File path: \(tempFilePath)") ReactLogger.log(level: .info, message: "File path: \(tempFilePath)")
@ -45,9 +47,11 @@ extension CameraView: AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureAud
guard let videoOutput = self.videoOutput else { guard let videoOutput = self.videoOutput else {
if self.video?.boolValue == true { if self.video?.boolValue == true {
return callback.reject(error: .session(.cameraNotReady)) callback.reject(error: .session(.cameraNotReady))
return
} else { } else {
return callback.reject(error: .capture(.videoNotEnabled)) callback.reject(error: .capture(.videoNotEnabled))
return
} }
} }
@ -58,7 +62,7 @@ extension CameraView: AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureAud
let enableAudio = self.audio?.boolValue == true let enableAudio = self.audio?.boolValue == true
let onFinish = { (status: AVAssetWriter.Status, error: Error?) -> Void in let onFinish = { (status: AVAssetWriter.Status, error: Error?) in
defer { defer {
self.recordingSession = nil self.recordingSession = nil
if enableAudio { if enableAudio {
@ -69,16 +73,15 @@ extension CameraView: AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureAud
} }
ReactLogger.log(level: .info, message: "RecordingSession finished with status \(status.descriptor).") ReactLogger.log(level: .info, message: "RecordingSession finished with status \(status.descriptor).")
if let error = error as NSError? { if let error = error as NSError? {
let description = error.description callback.reject(error: .capture(.unknown(message: "An unknown recording error occured! \(error.description)")), cause: error)
return callback.reject(error: .capture(.unknown(message: "An unknown recording error occured! \(description)")), cause: error)
} else { } else {
if status == .completed { if status == .completed {
return callback.resolve([ callback.resolve([
"path": self.recordingSession!.url.absoluteString, "path": self.recordingSession!.url.absoluteString,
"duration": self.recordingSession!.duration, "duration": self.recordingSession!.duration,
]) ])
} else { } else {
return callback.reject(error: .unknown(message: "AVAssetWriter completed with status: \(status.descriptor)")) callback.reject(error: .unknown(message: "AVAssetWriter completed with status: \(status.descriptor)"))
} }
} }
} }
@ -88,13 +91,15 @@ extension CameraView: AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureAud
fileType: fileType, fileType: fileType,
completion: onFinish) completion: onFinish)
} catch let error as NSError { } catch let error as NSError {
return callback.reject(error: .capture(.createRecorderError(message: nil)), cause: error) callback.reject(error: .capture(.createRecorderError(message: nil)), cause: error)
return
} }
// Init Video // Init Video
guard let videoSettings = videoOutput.recommendedVideoSettingsForAssetWriter(writingTo: fileType), guard let videoSettings = videoOutput.recommendedVideoSettingsForAssetWriter(writingTo: fileType),
!videoSettings.isEmpty else { !videoSettings.isEmpty else {
return callback.reject(error: .capture(.createRecorderError(message: "Failed to get video settings!"))) callback.reject(error: .capture(.createRecorderError(message: "Failed to get video settings!")))
return
} }
self.recordingSession!.initializeVideoWriter(withSettings: videoSettings, self.recordingSession!.initializeVideoWriter(withSettings: videoSettings,
isVideoMirrored: self.videoOutput!.isMirrored) isVideoMirrored: self.videoOutput!.isMirrored)
@ -172,7 +177,8 @@ extension CameraView: AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureAud
// Video Recording runs in the same queue // Video Recording runs in the same queue
if isRecording { if isRecording {
guard let recordingSession = recordingSession else { guard let recordingSession = recordingSession else {
return invokeOnError(.capture(.unknown(message: "isRecording was true but the RecordingSession was null!"))) invokeOnError(.capture(.unknown(message: "isRecording was true but the RecordingSession was null!")))
return
} }
switch captureOutput { switch captureOutput {

View File

@ -28,26 +28,31 @@ extension CameraView {
guard let photoOutput = self.photoOutput, guard let photoOutput = self.photoOutput,
let videoDeviceInput = self.videoDeviceInput else { let videoDeviceInput = self.videoDeviceInput else {
if self.photo?.boolValue == true { if self.photo?.boolValue == true {
return promise.reject(error: .session(.cameraNotReady)) promise.reject(error: .session(.cameraNotReady))
return
} else { } else {
return promise.reject(error: .capture(.photoNotEnabled)) promise.reject(error: .capture(.photoNotEnabled))
return
} }
} }
var photoSettings = AVCapturePhotoSettings() var photoSettings = AVCapturePhotoSettings()
if let photoCodecString = options["photoCodec"] as? String { if let photoCodecString = options["photoCodec"] as? String {
guard let photoCodec = AVVideoCodecType(withString: photoCodecString) else { guard let photoCodec = AVVideoCodecType(withString: photoCodecString) else {
return promise.reject(error: .capture(.invalidPhotoCodec)) promise.reject(error: .capture(.invalidPhotoCodec))
return
} }
if photoOutput.availablePhotoCodecTypes.contains(photoCodec) { if photoOutput.availablePhotoCodecTypes.contains(photoCodec) {
photoSettings = AVCapturePhotoSettings(format: [AVVideoCodecKey: photoCodec]) photoSettings = AVCapturePhotoSettings(format: [AVVideoCodecKey: photoCodec])
} else { } else {
return promise.reject(error: .parameter(.invalid(unionName: "PhotoCodec", receivedValue: photoCodecString))) promise.reject(error: .parameter(.invalid(unionName: "PhotoCodec", receivedValue: photoCodecString)))
return
} }
} }
if videoDeviceInput.device.isFlashAvailable, let flash = options["flash"] as? String { if videoDeviceInput.device.isFlashAvailable, let flash = options["flash"] as? String {
guard let flashMode = AVCaptureDevice.FlashMode(withString: flash) else { guard let flashMode = AVCaptureDevice.FlashMode(withString: flash) else {
return promise.reject(error: .parameter(.invalid(unionName: "FlashMode", receivedValue: flash))) promise.reject(error: .parameter(.invalid(unionName: "FlashMode", receivedValue: flash)))
return
} }
photoSettings.flashMode = flashMode photoSettings.flashMode = flashMode
} }
@ -63,7 +68,8 @@ extension CameraView {
} }
if #available(iOS 13.0, *), let qualityPrioritization = options["qualityPrioritization"] as? String { if #available(iOS 13.0, *), let qualityPrioritization = options["qualityPrioritization"] as? String {
guard let photoQualityPrioritization = AVCapturePhotoOutput.QualityPrioritization(withString: qualityPrioritization) else { guard let photoQualityPrioritization = AVCapturePhotoOutput.QualityPrioritization(withString: qualityPrioritization) else {
return promise.reject(error: .parameter(.invalid(unionName: "QualityPrioritization", receivedValue: qualityPrioritization))) promise.reject(error: .parameter(.invalid(unionName: "QualityPrioritization", receivedValue: qualityPrioritization)))
return
} }
photoSettings.photoQualityPrioritization = photoQualityPrioritization photoSettings.photoQualityPrioritization = photoQualityPrioritization
} }

View File

@ -227,10 +227,12 @@ public final class CameraView: UIView {
internal final func setTorchMode(_ torchMode: String) { internal final func setTorchMode(_ torchMode: String) {
guard let device = videoDeviceInput?.device else { guard let device = videoDeviceInput?.device else {
return invokeOnError(.session(.cameraNotReady)) invokeOnError(.session(.cameraNotReady))
return
} }
guard var torchMode = AVCaptureDevice.TorchMode(withString: torchMode) else { guard var torchMode = AVCaptureDevice.TorchMode(withString: torchMode) else {
return invokeOnError(.parameter(.invalid(unionName: "TorchMode", receivedValue: torch))) invokeOnError(.parameter(.invalid(unionName: "TorchMode", receivedValue: torch)))
return
} }
if !captureSession.isRunning { if !captureSession.isRunning {
torchMode = .off torchMode = .off
@ -245,7 +247,8 @@ public final class CameraView: UIView {
return return
} else { } else {
// torch mode is .auto or .on, but no torch is available. // torch mode is .auto or .on, but no torch is available.
return invokeOnError(.device(.torchUnavailable)) invokeOnError(.device(.torchUnavailable))
return
} }
} }
do { do {
@ -256,7 +259,8 @@ public final class CameraView: UIView {
} }
device.unlockForConfiguration() device.unlockForConfiguration()
} catch let error as NSError { } catch let error as NSError {
return invokeOnError(.device(.configureError), cause: error) invokeOnError(.device(.configureError), cause: error)
return
} }
} }

View File

@ -70,7 +70,8 @@ final class CameraViewManager: RCTViewManager {
final func focus(_ node: NSNumber, point: NSDictionary, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) { final func focus(_ node: NSNumber, point: NSDictionary, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
let promise = Promise(resolver: resolve, rejecter: reject) let promise = Promise(resolver: resolve, rejecter: reject)
guard let x = point["x"] as? NSNumber, let y = point["y"] as? NSNumber else { guard let x = point["x"] as? NSNumber, let y = point["y"] as? NSNumber else {
return promise.reject(error: .parameter(.invalid(unionName: "point", receivedValue: point.description))) promise.reject(error: .parameter(.invalid(unionName: "point", receivedValue: point.description)))
return
} }
let component = getCameraView(withTag: node) let component = getCameraView(withTag: node)
component.focus(point: CGPoint(x: x.doubleValue, y: y.doubleValue), promise: promise) component.focus(point: CGPoint(x: x.doubleValue, y: y.doubleValue), promise: promise)

View File

@ -63,11 +63,11 @@ __attribute__((objc_runtime_name("_TtC12VisionCamera10CameraView")))
#ifdef ENABLE_FRAME_PROCESSORS #ifdef ENABLE_FRAME_PROCESSORS
NSLog(@"FrameProcessorBindings: Creating Runtime Manager..."); NSLog(@"FrameProcessorBindings: Creating Runtime Manager...");
weakBridge = bridge; weakBridge = bridge;
auto runtime = vision::makeJSIRuntime(); auto runtime = vision::makeJSIRuntime();
reanimated::RuntimeDecorator::decorateRuntime(*runtime, "FRAME_PROCESSOR"); reanimated::RuntimeDecorator::decorateRuntime(*runtime, "FRAME_PROCESSOR");
runtime->global().setProperty(*runtime, "_FRAME_PROCESSOR", jsi::Value(true)); runtime->global().setProperty(*runtime, "_FRAME_PROCESSOR", jsi::Value(true));
auto callInvoker = bridge.jsCallInvoker; auto callInvoker = bridge.jsCallInvoker;
auto scheduler = std::make_shared<reanimated::REAIOSScheduler>(callInvoker); auto scheduler = std::make_shared<reanimated::REAIOSScheduler>(callInvoker);
runtimeManager = std::make_unique<reanimated::RuntimeManager>(std::move(runtime), runtimeManager = std::make_unique<reanimated::RuntimeManager>(std::move(runtime),
@ -78,7 +78,7 @@ __attribute__((objc_runtime_name("_TtC12VisionCamera10CameraView")))
NSLog(@"FrameProcessorBindings: Installing Frame Processor plugins..."); NSLog(@"FrameProcessorBindings: Installing Frame Processor plugins...");
auto& visionRuntime = *runtimeManager->runtime; auto& visionRuntime = *runtimeManager->runtime;
auto visionGlobal = visionRuntime.global(); auto visionGlobal = visionRuntime.global();
for (NSString* pluginKey in [FrameProcessorPluginRegistry frameProcessorPlugins]) { for (NSString* pluginKey in [FrameProcessorPluginRegistry frameProcessorPlugins]) {
auto pluginName = [pluginKey UTF8String]; auto pluginName = [pluginKey UTF8String];
@ -89,18 +89,16 @@ __attribute__((objc_runtime_name("_TtC12VisionCamera10CameraView")))
const jsi::Value& thisValue, const jsi::Value& thisValue,
const jsi::Value* arguments, const jsi::Value* arguments,
size_t count) -> jsi::Value { size_t count) -> jsi::Value {
auto frameHostObject = arguments[0].asObject(runtime).asHostObject(runtime); auto frameHostObject = arguments[0].asObject(runtime).asHostObject(runtime);
auto frame = static_cast<FrameHostObject*>(frameHostObject.get()); auto frame = static_cast<FrameHostObject*>(frameHostObject.get());
auto args = convertJSICStyleArrayToNSArray(runtime, auto args = convertJSICStyleArrayToNSArray(runtime,
arguments + 1, // start at index 1 since first arg = Frame arguments + 1, // start at index 1 since first arg = Frame
count - 1, // use smaller count count - 1, // use smaller count
callInvoker); callInvoker);
id result = callback(frame->frame, args); id result = callback(frame->frame, args);
return convertObjCObjectToJSIValue(runtime, result); return convertObjCObjectToJSIValue(runtime, result);
}; };
visionGlobal.setProperty(visionRuntime, pluginName, jsi::Function::createFromHostFunction(visionRuntime, visionGlobal.setProperty(visionRuntime, pluginName, jsi::Function::createFromHostFunction(visionRuntime,
@ -108,9 +106,9 @@ __attribute__((objc_runtime_name("_TtC12VisionCamera10CameraView")))
1, // frame 1, // frame
function)); function));
} }
[FrameProcessorPluginRegistry markInvalid]; [FrameProcessorPluginRegistry markInvalid];
NSLog(@"FrameProcessorBindings: Frame Processor plugins installed!"); NSLog(@"FrameProcessorBindings: Frame Processor plugins installed!");
#else #else
NSLog(@"Reanimated not found, Frame Processors are disabled."); NSLog(@"Reanimated not found, Frame Processors are disabled.");
@ -125,13 +123,13 @@ __attribute__((objc_runtime_name("_TtC12VisionCamera10CameraView")))
NSLog(@"FrameProcessorBindings: Failed to install Frame Processor Bindings - bridge was null!"); NSLog(@"FrameProcessorBindings: Failed to install Frame Processor Bindings - bridge was null!");
return; return;
} }
NSLog(@"FrameProcessorBindings: Installing Frame Processor Bindings for Bridge..."); NSLog(@"FrameProcessorBindings: Installing Frame Processor Bindings for Bridge...");
RCTCxxBridge *cxxBridge = (RCTCxxBridge *)weakBridge; RCTCxxBridge *cxxBridge = (RCTCxxBridge *)weakBridge;
if (!cxxBridge.runtime) { if (!cxxBridge.runtime) {
return; return;
} }
jsi::Runtime& jsiRuntime = *(jsi::Runtime*)cxxBridge.runtime; jsi::Runtime& jsiRuntime = *(jsi::Runtime*)cxxBridge.runtime;
NSLog(@"FrameProcessorBindings: Installing global functions..."); NSLog(@"FrameProcessorBindings: Installing global functions...");
@ -150,16 +148,16 @@ __attribute__((objc_runtime_name("_TtC12VisionCamera10CameraView")))
auto worklet = reanimated::ShareableValue::adapt(runtime, arguments[1], runtimeManager.get()); auto worklet = reanimated::ShareableValue::adapt(runtime, arguments[1], runtimeManager.get());
NSLog(@"FrameProcessorBindings: Successfully created worklet!"); NSLog(@"FrameProcessorBindings: Successfully created worklet!");
RCTExecuteOnMainQueue([worklet, viewTag, self]() -> void { RCTExecuteOnMainQueue([worklet, viewTag, self]() {
auto currentBridge = [RCTBridge currentBridge]; auto currentBridge = [RCTBridge currentBridge];
auto anonymousView = [currentBridge.uiManager viewForReactTag:[NSNumber numberWithDouble:viewTag]]; auto anonymousView = [currentBridge.uiManager viewForReactTag:[NSNumber numberWithDouble:viewTag]];
auto view = static_cast<CameraView*>(anonymousView); auto view = static_cast<CameraView*>(anonymousView);
dispatch_async(CameraQueues.videoQueue, [worklet, view, self]() -> void { dispatch_async(CameraQueues.videoQueue, [worklet, view, self]() {
NSLog(@"FrameProcessorBindings: Converting worklet to Objective-C callback..."); NSLog(@"FrameProcessorBindings: Converting worklet to Objective-C callback...");
auto& rt = *runtimeManager->runtime; auto& rt = *runtimeManager->runtime;
auto function = worklet->getValue(rt).asObject(rt).asFunction(rt); auto function = worklet->getValue(rt).asObject(rt).asFunction(rt);
view.frameProcessorCallback = convertJSIFunctionToFrameProcessorCallback(rt, function); view.frameProcessorCallback = convertJSIFunctionToFrameProcessorCallback(rt, function);
NSLog(@"FrameProcessorBindings: Frame processor set!"); NSLog(@"FrameProcessorBindings: Frame processor set!");
}); });
@ -184,10 +182,10 @@ __attribute__((objc_runtime_name("_TtC12VisionCamera10CameraView")))
RCTExecuteOnMainQueue(^{ RCTExecuteOnMainQueue(^{
auto currentBridge = [RCTBridge currentBridge]; auto currentBridge = [RCTBridge currentBridge];
if (!currentBridge) return; if (!currentBridge) return;
auto anonymousView = [currentBridge.uiManager viewForReactTag:[NSNumber numberWithDouble:viewTag]]; auto anonymousView = [currentBridge.uiManager viewForReactTag:[NSNumber numberWithDouble:viewTag]];
if (!anonymousView) return; if (!anonymousView) return;
auto view = static_cast<CameraView*>(anonymousView); auto view = static_cast<CameraView*>(anonymousView);
view.frameProcessorCallback = nil; view.frameProcessorCallback = nil;
NSLog(@"FrameProcessorBindings: Frame processor removed!"); NSLog(@"FrameProcessorBindings: Frame processor removed!");

View File

@ -13,6 +13,8 @@ private var delegatesReferences: [NSObject] = []
// MARK: - PhotoCaptureDelegate // MARK: - PhotoCaptureDelegate
class PhotoCaptureDelegate: NSObject, AVCapturePhotoCaptureDelegate { class PhotoCaptureDelegate: NSObject, AVCapturePhotoCaptureDelegate {
private let promise: Promise
required init(promise: Promise) { required init(promise: Promise) {
self.promise = promise self.promise = promise
super.init() super.init()
@ -24,19 +26,21 @@ class PhotoCaptureDelegate: NSObject, AVCapturePhotoCaptureDelegate {
delegatesReferences.removeAll(where: { $0 == self }) delegatesReferences.removeAll(where: { $0 == self })
} }
if let error = error as NSError? { if let error = error as NSError? {
return promise.reject(error: .capture(.unknown(message: error.description)), cause: error) promise.reject(error: .capture(.unknown(message: error.description)), cause: error)
return
} }
let error = ErrorPointer(nilLiteral: ()) let error = ErrorPointer(nilLiteral: ())
guard let tempFilePath = RCTTempFilePath("jpeg", error) guard let tempFilePath = RCTTempFilePath("jpeg", error)
else { else {
return promise.reject(error: .capture(.createTempFileError), cause: error?.pointee) promise.reject(error: .capture(.createTempFileError), cause: error?.pointee)
return
} }
let url = URL(string: "file://\(tempFilePath)")! let url = URL(string: "file://\(tempFilePath)")!
guard let data = photo.fileDataRepresentation() guard let data = photo.fileDataRepresentation() else {
else { promise.reject(error: .capture(.fileError))
return promise.reject(error: .capture(.fileError)) return
} }
do { do {
@ -45,7 +49,7 @@ class PhotoCaptureDelegate: NSObject, AVCapturePhotoCaptureDelegate {
let width = exif?["PixelXDimension"] let width = exif?["PixelXDimension"]
let height = exif?["PixelYDimension"] let height = exif?["PixelYDimension"]
return promise.resolve([ promise.resolve([
"path": tempFilePath, "path": tempFilePath,
"width": width as Any, "width": width as Any,
"height": height as Any, "height": height as Any,
@ -54,7 +58,7 @@ class PhotoCaptureDelegate: NSObject, AVCapturePhotoCaptureDelegate {
"thumbnail": photo.embeddedThumbnailPhotoFormat as Any, "thumbnail": photo.embeddedThumbnailPhotoFormat as Any,
]) ])
} catch { } catch {
return promise.reject(error: .capture(.fileError), cause: error as NSError) promise.reject(error: .capture(.fileError), cause: error as NSError)
} }
} }
@ -63,11 +67,8 @@ class PhotoCaptureDelegate: NSObject, AVCapturePhotoCaptureDelegate {
delegatesReferences.removeAll(where: { $0 == self }) delegatesReferences.removeAll(where: { $0 == self })
} }
if let error = error as NSError? { if let error = error as NSError? {
return promise.reject(error: .capture(.unknown(message: error.description)), cause: error) promise.reject(error: .capture(.unknown(message: error.description)), cause: error)
return
} }
} }
// MARK: Private
private let promise: Promise
} }

View File

@ -81,7 +81,7 @@ NSString *convertJSIStringToNSString(jsi::Runtime &runtime, const jsi::String &v
} }
NSArray* convertJSICStyleArrayToNSArray(jsi::Runtime &runtime, const jsi::Value* array, size_t length, std::shared_ptr<CallInvoker> jsInvoker) { NSArray* convertJSICStyleArrayToNSArray(jsi::Runtime &runtime, const jsi::Value* array, size_t length, std::shared_ptr<CallInvoker> jsInvoker) {
if (length == 0) return @[]; if (length < 1) return @[];
NSMutableArray *result = [NSMutableArray new]; NSMutableArray *result = [NSMutableArray new];
for (size_t i = 0; i < length; i++) { for (size_t i = 0; i < length; i++) {
// Insert kCFNull when it's `undefined` value to preserve the indices. // Insert kCFNull when it's `undefined` value to preserve the indices.